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$
1
  • $\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, 2016 at 13:50

2 Answers 2

8
$\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$
3
  • $\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, 2016 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, 2016 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, 2016 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$
3
  • $\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, 2016 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, 2016 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, 2016 at 7:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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