How to understand the different output of two UnsetShared?

Update 2

In v11.0.0, situation seems getting worse. UnsetShared doesn't unshare at all. Even the code in help documentation doesn't work as expected.

Update

From technical support,

Thank you for contacting Wolfram Technical Support. I understand that you are reporting an issue with UnsetShared deleting the shared variable after a second evaluation. There seems to be an issue and I was able to reproduce it. I have forwarded an incident report to our developers and have included your contact information in my report.

Original Post

In[1]:= z = 1; SetSharedVariable[z];
ParallelEvaluate[z]
ParallelEvaluate[Print@z];


(==> Out[2]= {1, 1})

(during the evaluation)
(kernel 1) 1
(kernel 2) 1

Looks resonable. However,

In[4]:= UnsetShared[z];
ParallelEvaluate[Print@z];


(during the evaluation)
(kernel 1) 1
(kernel 2) 1

this is pretty strange since the z is not recognized by the subkernels anymore.

The most strange part is if you evaluate the In[4] again :

In[6]:= UnsetShared[z];
ParallelEvaluate[Print@z];


(during the evaluation)
(kernel 1) z
(kernel 2) z

This really disturbes me. Is this a bug or did I misunderstand something? (Windows 10, Mathematica v10.4)

• This behaviour is new in 10.4 (and I can confirm it with 10.4.1). In 10.3.1 I get only z printed after the first UnsetShared. I smell a bug. Can you contact support and report it to them? If they respond, can you let us know their response? – Szabolcs Apr 26 '16 at 10:54
• @Szabolcs Glad to be supported by you. I'll contact the technique support and keep updating the post. – luyuwuli Apr 26 '16 at 11:10

This is an extended comment.

This behaviour is new in 10.4. I can reproduce it with 10.4.1 on OS X, but not with 10.3.1.

This may be related: DistributeDefinitions and synchronization in Mathematica 10

We can try to analyse what happens like this:

z := (Print[\$KernelID]; 1);
SetSharedVariable[z];

ParallelEvaluate[z]
ParallelEvaluate[Print@Definition[z]]
ParallelEvaluate[Print@z];


This will let us figure out:

• Where does z get evaluated? Since it's a shared variable, it is supposed to evaluate on the main kernel, then the result must be passed back to the subkernel.

• What does z evaluate to?

• What is the definition of z on the subkernels?

At this point we get what I would expect, and everything is in agreement with previous versions:

• z is evaluated on the main kernel
• z evaluates to 1
• z has a special definition on the subkernel that triggers the callback to the main kernel (I won't quote the output because it is very large)

Now we UnsetShared ...

UnsetShared[z];
ParallelEvaluate[Print@Definition[z]];
ParallelEvaluate[Print[z]]


... and we find that

• z evaluates on the subkernels
• z evaluates to 1 (which I consider wrong, like you).
• z has the same definition on the subkernels as on the main kernel, which is wrong, and differs from previous versions. This definition should not have been distributed by ParallelEvaluate.

And we do it again:

UnsetShared[z];
ParallelEvaluate[Print@Definition[z]];
ParallelEvaluate[Print[z]]


Now everything is back to normal. z has no definition on the subkernel any longer.

• Thanks for your comment. I've send the report.. and I also have a quesion that if all the shared definitions and variables are evaluated at the master kernel, then what's point of parallelization? I've read the tutorial of ParallelTools (haven't finished yet), still I can't understand why they design it this way. – luyuwuli Apr 26 '16 at 11:33
• @luyuwuli Ideally you would design your algorithm in a way that subkernels do not need to communicate with each other at all. They are assigned tasks by the master kernel, they complete the tasks and return the result. But sometimes this is not possible. Some algorithms require communication between the parallel threads. In all cases, this brings a performance hit. In Mathematica it brings a big performance hit. But if the communication is minimized, it might still be worth doing it and parallelization may still provide a speedup. – Szabolcs Apr 26 '16 at 11:40
• @luyuwuli Generally: try to avoid SetSharedVariable and SetSharedFunction because they might slow down your program so much that it will perform worse than the non-parallel version. Yet there are certain cases when these are still useful, e.g. if the subkernels do a very slow piece of computation that might take a few seconds to complete, and at the end of this they report their progress to the master kernel. In most cases that I deal with the performance hit is too much though. – Szabolcs Apr 26 '16 at 11:42
• Yes. That's what I've worried about the SetSharedFunction. I previously mixed up SetSharedXXX with DistributeDefinitions. Can I put it this way that SetSharedXXX is a marker in master kernel that subkernels should know or could modify, while DistributeDefinitions actually makes copies and send them to the subkernels so these subkernels don't know eath other? – luyuwuli Apr 26 '16 at 11:52
• @luyuwuli Yes. A shared variable is always evaluated on the master kernel and is always set on the master kernel. Normally you use DistributeDefinitions (this actually happens automatically with most parallelization functions except ParallelEvaluate), which creates independent copies of symbols on the subkernels. – Szabolcs Apr 26 '16 at 12:28