6
$\begingroup$

This question is related to my previous one here. I opened a new question because I think that the root cause is different though. BTW I use MMA 9 on a mac OS X 10.11 (El Capitan).

I put here a minimal example. I define a constant:

const`precisionRate = 10

and a function which uses this constant:

f = Function[x, N[x^2, const`precisionRate]];

when I look at the definition of my function I get as expected:

def

If I run it I get as expected:

f[2]
(*4.000000000*)

Using it within table also works:

Table[{y, f[y]}, {y, -1, 1, 0.1}]
(*{{-1., 1.}, {-0.9, 0.81}, {-0.8, 0.64}, {-0.7, 0.49}, {-0.6, 
0.36}, {-0.5, 0.25}, {-0.4, 0.16}, {-0.3, 0.09}, {-0.2, 
0.04}, {-0.1, 0.01}, {0., 0.}, {0.1, 0.01}, {0.2, 0.04}, {0.3, 
0.09}, {0.4, 0.16}, {0.5, 0.25}, {0.6, 0.36}, {0.7, 0.49}, {0.8, 
0.64}, {0.9, 0.81}, {1., 1.}}*)

But when I run:

ParallelTable[{y, f[y]}, {y, -1, 1, 0.1}]

I get an error (from each kernel separately of course):

enter image description here

Why does prallelization screw this up?

$\endgroup$
  • $\begingroup$ This is closely related, almost a duplicate: mathematica.stackexchange.com/q/111448/12 The answer from there should answer your question too. But since your issue is much simpler, I think it's better not to mark as duplicate. I wrote a separate answer here. $\endgroup$ – Szabolcs Oct 9 '16 at 13:50
6
$\begingroup$

I am not 100% comfortable about this aspect of parallelization, so this is not going to be a full answer, but here are some hints:

In order for a piece of code to run in parallel, all definitions it uses must be copied to the subkernels. This is called "distributing" the definitions and can be done manually by DistributeDefinitions. It is also done automatically by most parallel functions (such as ParallelTable). A notable exception was ParallelEvaluate until version 10.4 .

Automatic distribution is done only for $Context. This is controlled by $DistributedContexts.

Why not distribute definitions for all contexts? Because for a package to work properly, it may not be sufficient to just copy all definitions from its context. The package may do things upon loading which are more complex than issuing definitions. E.g. it may load LibraryFunctions. Thus packages are meant to be loaded on parallel kernels using ParallelNeeds instead of just copying their definitions over from the main kernel.

What can you do then?

Either

DistributeDefinitions[const`precisionRate]

to manually distribute the definitions of this one symbol, or

$DistributedContexts := {$Context, "const`"}

to automatically distribute everything from the const` context. The second solution looks cleaner to me.

$\endgroup$
  • $\begingroup$ Thanks. I do indeed have multiple constants under this context, and therefore your second solution does seem better. I'm interested though in your remark of parallel needs. I do indeed load some functions using the Get function, while all of my definitions belong to either to the const` context or Global` . Is there an advantage to using the parallel needs in terms of performance? Is my code prone to make mistakes if I don't use parallel needs? $\endgroup$ – Yair M Oct 9 '16 at 16:54
  • $\begingroup$ @YairM Provided that your package only has definitions: I don't think so. Just distributing them should be fine. But I may be wrong and I don't have a 100% understanding of the parallel stuff. $\endgroup$ – Szabolcs Oct 9 '16 at 17:03
  • $\begingroup$ I just read the bigger discussion which you referenced in your comment to my question. In my real code, within the parallel table I call another function (for each iteration the arguments change), and this function contains a Module within it. This function was defined in the file which I called using Get. Should I worry about some corruption of cache or memory. I do see the memory leaks which I try to fix by clearing everything I can manually before leaving the function. I don't see any erratic behavior in my final results though, so maybe it works. $\endgroup$ – Yair M Oct 9 '16 at 17:23
4
$\begingroup$

You need to SetSharedVariable on const`precisionRate. ParallelTable is not sharing this definition. Perhaps because it is not in the context of f.

Launch the kernels and then share.

LaunchKernels[]
SetSharedVariable[const`precisionRate]

Then ParallelTable works as expected.

ParallelTable[{y, f[y]}, {y, -1, 1, 0.1}]

Remember to UnsetShared.

UnsetShared[const`precisionRate]

Hope this helps.

$\endgroup$
  • $\begingroup$ This is incorrect. SetSharedVariable is not needed and is even harmful because it will force main kernel callbacks which usually kill performance. This is about distributing definitions for symbols which are not in Global` . $\endgroup$ – Szabolcs Oct 9 '16 at 13:46
  • $\begingroup$ @Szabolcs So correct concept with an implementation that can be view as not ideal? It does work so I would not say it is incorrect. However, thanks for the further details. Clarifications like this are very helpful. $\endgroup$ – Edmund Oct 9 '16 at 18:59
  • $\begingroup$ I meant "not correct" in the sense that what's missing here (that would normally be present) is not the "shared" flag on the symbol but the "distributed" one. SetSharedVariable has a different purpose: to make the variable "settable" on all subkernels. There is no need for this in the OP's application. If every symbol that's supposed to be distributed would be shared instead, then parallelization would provide no speedup whatsoever, but a significant slowdown. $\endgroup$ – Szabolcs Oct 10 '16 at 7:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.