Remote Definitions

Parallel kernels do not have access to the values of variables defined in the master kernel, nor do they have access to locally defined functions.

The Wolfram Language contains a command (RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions]) that makes it easy to transport local variables and definitions to all parallel kernels. The main advantage of this method is that the application package does not need to be installed on the remote kernels. All definitions are sent through the existing connection to the remote kernels.

Distributing Definitions

Distributing definitions.

(RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions]) has the attribute (RefLink[HoldAll, paclet:ref/HoldAll]) to prevent the evaluation of the symbols.

(RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions]) exports the following kinds of definitions: (RefLink[OwnValues, paclet:ref/OwnValues]), (RefLink[DownValues, paclet:ref/DownValues]), SubValues, (RefLink[UpValues, paclet:ref/UpValues]), DefaultValues, NValues.

(RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions]) sets the attributes of the remote symbols equal to the locally defined attributes, except for attributes such as (RefLink[Protected, paclet:ref/Protected]) and (RefLink[Locked, paclet:ref/Locked]).

Any old definitions existing on the remote side are cleared before the new definitions are made.

Examples

Start several parallel kernels.

ParallelEvaluate[ $ProcessID]

Define a variable with a value and a function with attributes.

var=5;

SetAttributes[func,Listable]
func[r_]:=r^2

The remote kernels do not know the symbol var, as demonstrated with the next evaluation.

ParallelEvaluate[Names["var"]]

Here is a subtle point. The following remote evaluation seems to work, even though the symbols are not defined on the remote side.

ParallelEvaluate[func[var]]

The reason is that the remote kernels return the unevaluated expression func[var], because the function and variable are not defined on the remote kernel. The master kernel evaluates the returned results further, but it does so sequentially.

You can easily produce an example where the difference between remote and local evaluation becomes apparent.

On the local kernel, the symbol var evaluates to 5, and the (RefLink[Head, paclet:ref/Head]) of 5 is (RefLink[Integer, paclet:ref/Integer]).

Head[var]

On the remote kernels, var stays a symbol, and its head is (RefLink[Symbol, paclet:ref/Symbol]).

ParallelEvaluate[Head[var]]

You can export the local definitions to the remote kernels.

DistributeDefinitions[var,func]

Now the remote evaluation gives the same result as the local one.

ParallelEvaluate[Head[var]]

Automatic Distribution of Definitions

Higher-level parallel commands, such as (RefLink[Parallelize, paclet:ref/Parallelize]), (RefLink[ParallelTable, paclet:ref/ParallelTable]), (RefLink[ParallelSum, paclet:ref/ParallelSum]), … will automatically distribute definitions of symbols occurring in their arguments.

For this parallel table, the function f and the iterator bound n will evaluate on the subkernels, so their definitions need to be distributed to make it work.

f[x_,y_]:=x^y
{m,n}={4,2};

ParallelTable[f[i,j],{i,m},{j,n}]

This automatic distribution happens for any functions and variables you define interactively, within the same notebook (technically, for all symbols in the default context). Definitions from other contexts, such as functions from packages, are not distributed automatically.

A symbol ctx`s from a context other than the default context is not distributed automatically.

ctx`s:=$KernelID

As a result, the symbol is returned unevaluated from the remote kernels, and is evaluated only after the parallel computation is done, where (RefLink[$KernelID, paclet:ref/$KernelID]) is zero.

ParallelTable[ctx`s,{4}]

You can distribute such symbols using (RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions]).

DistributeDefinitions[ctx`s];

ParallelTable[ctx`s,{4}]

Distributing Contexts

(RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions])["Context`"] exports all definitions for all symbols in the given context. Thus, you can use the following to make all your interactively entered definitions known to the remote kernels.

DistributeDefinitions["Global`"]

Exporting the context of a package you have loaded may not have the same effect on the remote kernels as loading the package on each remote kernel. The reason is that loading a package may perform certain initializations and it may also define auxiliary functions in other contexts (such as a private context). Also, a package may load additional auxiliary packages that establish their own contexts.

(RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions])["Context`"] is useful for exporting contexts for definitions that you have explicitly set up to be used on remote kernels. There is a separate command (RefLink[ParallelNeeds, paclet:ref/ParallelNeeds]) for remote loading of packages.

Parallel`Developer`ClearKernels[] clears any definitions for symbols in the Global` context on remote kernels.

Loading Packages on Remote Kernels

Loading packages.

(RefLink[ParallelNeeds, paclet:ref/ParallelNeeds])["Context`"] is essentially equivalent to (RefLink[ParallelEvaluate, paclet:ref/ParallelEvaluate])[(RefLink[Needs, paclet:ref/Needs])["Context`"]], but it is remembered, and any newly launched remote kernels will be initialized as well.

Exporting the context of a package you have loaded may not have the same effect on the remote kernels as loading the package on each remote kernel with (RefLink[ParallelNeeds, paclet:ref/ParallelNeeds])[]. The reason is that loading a package may perform certain initializations, and it may also define auxiliary functions in other contexts (such as a private context). Also, a package may load additional auxiliary packages that establish their own contexts.

The next two commands load the Wolfram Language package FiniteFields` on the master kernel and all remote kernels.

Needs["FiniteFields`"]

ParallelNeeds["FiniteFields`"];

Note that Wolfram Language packages available to the master kernel may not be available on remote kernels from older versions of the Wolfram System.

Example: Eigenvalues of Matrices

Definitions

The parameter prec gives the desired precision for the computation of the eigenvalues of a random n×n matrix.

prec=18;

The function mat generates a random n×n matrix with numeric entries.

mat[n_]:=RandomReal[{-1,1},{n,n},WorkingPrecision->prec]

The function tf measures the time it takes to find the eigenvalues.

tf[n_]:=Timing[Eigenvalues[mat[n]]][[1]]

It is enough to distribute the definition of the main function tf. Any values it depends on will be distributed automatically.

DistributeDefinitions[tf]

A Sample Run

Here you measure the time it takes to find the eigenvalues of 5×5 to 25×25 matrices. Because the computations may happen on remote computers that differ in their processor speeds, the results do not necessarily form an increasing sequence.

ParallelMap[tf,{50,60,70,80}]

Alternatively, you can perform the same computation on each parallel processor to measure their relative speed. Here you find the speed of calculation of the eigenvalues of a 20×20 matrix on each of the parallel processors.

ParallelEvaluate[tf[70]]