Documentation Center

  • Trials
  • Product Updates

Programming Considerations

MATLAB Path

All workers executing a parfor-loop must have the same MATLAB® search path as the client, so that they can execute any functions called in the body of the loop. Therefore, whenever you use cd, addpath, or rmpath on the client, it also executes on all the workers, if possible. For more information, see the parpool reference page. When the workers are running on a different platform than the client, use the function pctRunOnAll to properly set the MATLAB search path on all workers.

Functions files that contain parfor-loops must be available on the search path of the workers in the pool running the parfor, or made available to the workers by the AttachedFiles or AdditionalPaths setting of the parallel pool.

Error Handling

When an error occurs during the execution of a parfor-loop, all iterations that are in progress are terminated, new ones are not initiated, and the loop terminates.

Errors and warnings produced on workers are annotated with the worker ID and displayed in the client's Command Window in the order in which they are received by the client MATLAB.

The behavior of lastwarn is unspecified at the end of the parfor if used within the loop body.

Limitations

Unambiguous Variable Names

If you use a name that MATLAB cannot unambiguously distinguish as a variable inside a parfor-loop, at parse time MATLAB assumes you are referencing a function. Then at run-time, if the function cannot be found, MATLAB generates an error. (See Variable Names in the MATLAB documentation.) For example, in the following code f(5) could refer either to the fifth element of an array named f, or to a function named f with an argument of 5. If f is not clearly defined as a variable in the code, MATLAB looks for the function f on the path when the code runs.

parfor i=1:n
   ...
   a = f(5);
   ...
end

Transparency

The body of a parfor-loop must be transparent, meaning that all references to variables must be "visible" (i.e., they occur in the text of the program).

In the following example, because X is not visible as an input variable in the parfor body (only the string 'X' is passed to eval), it does not get transferred to the workers. As a result, MATLAB issues an error at run time:

X = 5;
parfor ii = 1:4
    eval('X');
end

Similarly, you cannot clear variables from a worker's workspace by executing clear inside a parfor statement:

parfor ii= 1:4
    <statements...>
    clear('X')  % cannot clear: transparency violation
    <statements...>
end

As a workaround, you can free up most of the memory used by a variable by setting its value to empty, presumably when it is no longer needed in your parfor statement:

parfor ii= 1:4
    <statements...>
    X = [];
    <statements...>
end

Examples of some other functions that violate transparency are evalc, evalin, and assignin with the workspace argument specified as 'caller'; save and load, unless the output of load is assigned to a variable. Running a script from within a parfor-loop can cause a transparency violation if the script attempts to access (read or write) variables of the parent workspace; to avoid this issue, convert the script to a function and call it with the necessary variables as input or output arguments.

MATLAB does successfully execute eval and evalc statements that appear in functions called from the parfor body.

Sliced Variables Referencing Function Handles

Because of the way sliced input variables are segmented and distributed to the workers in the parallel pool, you cannot use a sliced input variable to reference a function handle. If you need to call a function handle with the parfor index variable as an argument, use feval.

For example, suppose you had a for-loop that performs:

B = @sin;
for ii = 1:100
    A(ii) = B(ii);
end

A corresponding parfor-loop does not allow B to reference a function handle. So you can work around the problem with feval:

B = @sin;
parfor ii = 1:100
    A(ii) = feval(B, ii);
end

Nondistributable Functions

If you use a function that is not strictly computational in nature (e.g., input, plot, keyboard) in a parfor-loop or in any function called by a parfor-loop, the behavior of that function occurs on the worker. The results might include hanging the worker process or having no visible effect at all.

Nested Functions

The body of a parfor-loop cannot make reference to a nested function. However, it can call a nested function by means of a function handle.

Nested Loops

The body of a parfor-loop cannot contain another parfor-loop. But it can call a function that contains another parfor-loop.

However, because a worker cannot open a parallel pool, a worker cannot run the inner nested parfor-loop in parallel. This means that only one level of nested parfor-loops can run in parallel. If the outer loop runs in parallel on a parallel pool, the inner loop runs serially on each worker. If the outer loop runs serially in the client (e.g., parfor specifying zero workers), the function that contains the inner loop can run the inner loop in parallel on workers in a pool.

The body of a parfor-loop can contain for-loops. You can use the inner loop variable for indexing the sliced array, but only if you use the variable in plain form, not part of an expression. For example:

A = zeros(4,5);
parfor j = 1:4
    for k = 1:5
        A(j,k) = j + k;
    end
end
A

Further nesting of for-loops with a parfor is also allowed.

Limitations of Nested for-Loops.  For proper variable classification, the range of a for-loop nested in a parfor must be defined by constant numbers or variables. In the following example, the code on the left does not work because the for-loop upper limit is defined by a function call. The code on the right works around this by defining a broadcast or constant variable outside the parfor first:

InvalidValid
A = zeros(100, 200);
parfor i = 1:size(A, 1)
   for j = 1:size(A, 2)
      A(i, j) = plus(i, j);
   end
end
A = zeros(100, 200);
n = size(A, 2);
parfor i = 1:size(A,1)
   for j = 1:n
      A(i, j) = plus(i, j);
   end
end

The index variable for the nested for loop must never be explicitly assigned other than in its for statement. When using the nested for-loop variable for indexing the sliced array, you must use the variable in plain form, not as part of an expression. For example, the following code on the left does not work, but the code on the right does:

InvalidValid
A = zeros(4, 11);
parfor i = 1:4
   for j = 1:10
      A(i, j + 1) = i + j;
   end
end
A = zeros(4, 11);
parfor i = 1:4
   for j = 2:11
      A(i, j) = i + j - 1;
   end
end

If you use a nested for-loop to index into a sliced array, you cannot use that array elsewhere in the parfor-loop. In the following example, the code on the left does not work because A is sliced and indexed inside the nested for-loop; the code on the right works because v is assigned to A outside the nested loop:

InvalidValid
A = zeros(4, 10);
parfor i = 1:4
    for j = 1:10
        A(i, j) = i + j;
    end
    disp(A(i, 1))
end
A = zeros(4, 10);
parfor i = 1:4
    v = zeros(1, 10);
    for j = 1:10
        v(j) = i + j;
    end
    disp(v(1))
    A(i, :) = v;
end

Inside a parfor, if you use multiple for-loops (not nested inside each other) to index into a single sliced array, they must loop over the same range of values. Furthermore, a sliced output variable can be used in only one nested for-loop. In the following example, the code on the left does not work because j and k loop over different values; the code on the right works to index different portions of the sliced array A:

InvalidValid
A = zeros(4, 10);
parfor i = 1:4
   for j = 1:5
      A(i, j) = i + j;
   end
   for k = 6:10
      A(i, k) = pi;
   end
end
A = zeros(4, 10);
parfor i = 1:4
   for j = 1:10
      if j < 6
         A(i, j) = i + j;
      else
         A(i, j) = pi;
      end
   end
end

Nested spmd Statements

The body of a parfor-loop cannot contain an spmd statement, and an spmd statement cannot contain a parfor-loop.

Break and Return Statements

The body of a parfor-loop cannot contain break or return statements.

Global and Persistent Variables

The body of a parfor-loop cannot contain global or persistent variable declarations.

Handle Classes

You can send handle objects as inputs to the body of a parfor-loop, but any changes made to handle classes on the workers during loop iterations are not automatically propagated back to the client. That is, changes made inside the loop are not automatically reflected after the loop.

To get the changes back to the client after the loop, explicitly assign the modified handle objects to output variables of the parfor-loop. In the following example, maps is a sliced input/output variable:

maps = {containers.Map(),containers.Map(),containers.Map()}; 
parfor ii = 1:numel(maps)
    mymap = maps{ii};   % input slice assigned to local copy
    for jj = 1:1000
        mymap(num2str(jj)) = rand;
    end
    maps{ii} = mymap;   % modified local copy assigned to output slice
end 

P-Code Scripts

You can call P-code script files from within a parfor-loop, but P-code script cannot contain a parfor-loop.

Structure Arrays in parfor-Loops

Creating Structures as Temporaries.  You cannot create a structure in a parfor-loop by using dot-notation assignment. For example, in the following code both lines inside the loop generate a classification error.

parfor i = 1:4
   temp.myfield1 = rand();
   temp.myfield2 = i;
end 

The workaround is to use the struct function to create the structure in the loop, or at least to create the first field. The following code shows two such solutions.

parfor i = 1:4
    temp = struct();
    temp.myfield1 = rand();
    temp.myfield2 = i;
end 
parfor i = 1:4
    temp = struct('myfield1',rand(),'myfield2',i);
end

Slicing Structure Fields.  You cannot use structure fields as sliced input or output arrays in a parfor-loop; that is, you cannot use the loop variable to index the elements of a structure field. For example, in the following code both lines in the loop generate a classification error because of the indexing:

parfor i = 1:4
    outputData.outArray1(i) = 1/i;
    outputData.outArray2(i) = i^2;
end 

The workaround for sliced output is to employ separate sliced arrays in the loop, and assign the structure fields after the loop is complete, as shown in the following code.

parfor i = 1:4
    outArray1(i) = 1/i;
    outArray2(i) = i^2;
end
outputData = struct('outArray1',outArray1,'outArray2',outArray2); 

The workaround for sliced input is to assign the structure field to a separate array before the loop, and use that new array for the sliced input.

inArray1 = inputData.inArray1;
inArray2 = inputData.inArray2;
parfor i = 1:4
    temp1 = inArray1(i);
    temp2 = inArray2(i);
end

Scalar Expansion with Sliced Outputs

You cannot use scalar expansion to define a set of values assigned to a sliced output array. For example, the following code attempts to expand the value idx for assignment to each element of the vector defined by x(:,idx); this generates an error.

x = zeros(10,12);
parfor idx = 1:12
  x(:,idx) = idx;
end

The following code offers a suggested workaround for this limitation.

x = zeros(10,12);
parfor idx = 1:12
   x(:,idx) = repmat(idx,10,1);
end

Using Objects in parfor-Loops

If you are passing objects into or out of a parfor-loop, the objects must properly facilitate being saved and loaded. For more information, see Understanding the Save and Load Process.

Performance Considerations

Slicing Arrays

If a variable is initialized before a parfor-loop, then used inside the parfor-loop, it has to be passed to each MATLAB worker evaluating the loop iterations. Only those variables used inside the loop are passed from the client workspace. However, if all occurrences of the variable are indexed by the loop variable, each worker receives only the part of the array it needs. For more information, see Where to Create Arrays.

Local vs. Cluster Workers

Running your code on local workers might offer the convenience of testing your application without requiring the use of cluster resources. However, there are certain drawbacks or limitations with using local workers. Because the transfer of data does not occur over the network, transfer behavior on local workers might not be indicative of how it will typically occur over a network. For more details, see Optimizing on Local vs. Cluster Workers.

Compatibility with Earlier Versions of MATLAB Software

In versions of MATLAB prior to 7.5 (R2007b), the keyword parfor designated a more limited style of parfor-loop than what is available in MATLAB 7.5 and later. This old style was intended for use with codistributed arrays (such as inside an spmd statement or a communicating job), and has been replaced by a for-loop that uses drange to define its range; see Looping Over a Distributed Range (for-drange).

The past and current functionality of the parfor keyword is outlined in the following table:

FunctionalitySyntax Prior to MATLAB 7.5Current Syntax
Parallel loop for codistributed arrays
parfor i = range
  loop body
    .
    .
end
for i = drange(range)
  loop body
    .
    .
end
Parallel loop for implicit distribution of workNot Implemented
parfor i = range
  loop body
    .
    .
end

Was this topic helpful?