I believe the hypothesis of Szabolcs made in the comments is correct, and Mathematica only distributes definitions it deems to be "new".
Digging a little into the definition of DistributeDefinitions
, it calls Parallel`Protected`DistDefs
, which then calls Parallel`Parallel`Private`updatedDefs
. When the definitions of f
have not yet been distributed, updatedDefs
returns them untouched and creates the downvalue Parallel`Parallel`Private`$distributedDefs[HoldForm[f]]
, which in this case takes the form
Parallel`Parallel`Private`$distributedDefs[HoldForm[f]] =
{OwnValues -> {}, SubValues -> {}, UpValues -> {},
DownValues -> {HoldPattern[f[1]] -> {2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
HoldPattern[f[2]] -> {3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
HoldPattern[f[3]] -> {4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
NValues -> {}, FormatValues -> {}, DefaultValues -> {},
Messages -> {}, Attributes -> {}}
When DistributeDefinitions
is called again without having modified f
, updateDefs
deletes the definitions of f
from the the list of definitions to be distributed because
Parallel`Parallel`Private`updatedDefs[s : "HoldForm"[_Symbol] -> vals_List, True] /;
Parallel`Parallel`Private`$distributedDefs[s] === vals :=
Sequence @@ {}
The solution to force a redistribution of definitions is to unset the appropriate $distributedDefs
beforehand:
f[1] = Range[10] + 1;
f[2] = Range[10] + 2;
f[3] = Range[10] + 3;
ParallelEvaluate[Clear[f]];
Parallel`Parallel`Private`$distributedDefs[HoldForm[f]] =.
DistributeDefinitions[f]
(* {f} *)
ParallelEvaluate[DownValues[f]]
(* {{HoldPattern[f[1]]:>{2,3,4,5,6,7,8,9,10,11},
HoldPattern[f[2]]:>{3,4,5,6,7,8,9,10,11,12},
HoldPattern[f[3]]:>{4,5,6,7,8,9,10,11,12,13}}
,
{HoldPattern[f[1]]:>{2,3,4,5,6,7,8,9,10,11},
HoldPattern[f[2]]:>{3,4,5,6,7,8,9,10,11,12},
HoldPattern[f[3]]:>{4,5,6,7,8,9,10,11,12,13}}} *)
This sets the definitions in the subkernels correctly even when evaluated multiple times.
The simpler option would of course be not to clear f
in the subkernels by hand, as DistributeDefinitions
does that in any case according to the documentation. But I guess this behavior is generally good to know about, if the subkernels run code that actively modifies the local definitions.
Definition[f]
is tricky. It does not evaluate, it just formats in a certain way. TryParallelEvaluate[Echo@Definition[f]]
to see thatf
has no definitions on the subkernels. $\endgroup$f
is already distributed, no need to touch it until it changes on the main kernel again". You are not supposed to mess with it on the subkernel, as distribution is one way only (main kernel -> subkernel) and the system assumes that it is fully managing the definitions off
on the subkernel. It assumes that you are not interfering. $\endgroup$DistributeDefinitions[f]
does nothing as the system believes that distribution has already happened, and there's no need to do it again. Notice that it returns{}
. That means that nothing was distributed. $\endgroup$