functions inside a matlab parfor loop

2.9k Views Asked by At

Can you use functions inside a matlab parfor loop? for instance I have a code that looks like:

matlabpool open 2
Mat=zeros(100,8);
parfor(i=1:100)
    Mat(i,:)=foo();
end

Inside the function I have a bunch of other variables. In particular there is a snippet of code that looks like this:

function z=foo()
    err=1;
    a=zeros(10000,1);
    p=1;

    while(err>.0001)

        %statements to update err 
        %   .
        %   .
        %   .

        p=p+1;

        %if out of memory allocate more
        if(p>length(a))
            a=[a;zeros(length(a),1)];
        end
    end

    %trim output after while loop
    if(p<length(a))
        a(p+1:end)=[];
    end

    %example output
    z=1:8;

end    

I read somewhere that all variables that grow inside of a for loop nested inside of a matlab parfor loop must be preallocated, but in this case I have a variable that is preallocated, but might grow later. matlab did not give me any errors when i used mlint, but I was wondering if there are issues that I should be aware of.

Thanks,

-akt

2

There are 2 best solutions below

1
On

According to Mathworks' documentation, your implementation of the matrix Mat is a sliced variable. That means you update different "slices" of the same matrix in different iterations, but the iterations do not affect each other. There is no data dependency between the loops. So you are ok to go.

Growing a inside function foo does not affect the parfor, because a is a regular variable located in foo's stack. You can do anything with a.

There do exist several issues to notice:

Don't use i and j as iteration counters

Defining i or j in any purpose is bad.

I have never been bored to refer people to this post - Using i and j as variables in Matlab.

Growing a is bad

Every time you do a=[a;zeros(length(a),1)]; the variable is copied as a whole into a new empty place in RAM. As its size doubles each time, it could be a disaster. Not hard to imagine.

A lighter way to "grow" -

% initialize a list of pointers
p = 1;
cc = 1;
c{1} = zeros(1000,1);
% use it
while (go_on)
    % do something
    disp(c{cc})
    ....

    p=p+1;
    if (p>1000)
        cc = cc+1;
        c{cc} = zeros(1000,1);
        p = 1;
    end
end

Here, you grow a list of pointers, a cell array c. It's smaller, faster, but still it needs copying in memory.

Use minimal amount of memory

Suppose you only need a small part of a, that is, a(end-8:end), as the function output. (This assumption bases on the caller Mat(i,:)=foo(); where size(Mat, 2)=8. )

Suppose err is not related to previous elements of a, that is, a(p-1), a(p-2), .... (I will loosen this assumption later.)

You don't have to keep all previous results in memory. If a is used up, just throw it.

% if out of memory, don't allocate more; flush it
if (p>1000)
    p = 1;
    a = zeros(1000,1);
end

The second assumption may be loosen to that you only need a certain number of previous elements, while this number is already known (hopefully it's small). For example,

% if out of memory, flush it, but keep the last 3 results
if (p>1000)
    a = [a(end-3:end); zeros(997,1)];
    p = 4;
end

Trimming is not that complicated

% trim output after while loop
a(p+1:end)=[];

Proof:

>> a=1:10
a =
     1     2     3     4     5     6     7     8     9    10
>> a(3:end)=[]
a =
     1     2
>> a=1:10
a =
     1     2     3     4     5     6     7     8     9    10
>> a(11:end)=[]
a =
     1     2     3     4     5     6     7     8     9    10
>> 

The reason is end is 10 (although you can't use it as a stanalone variable), and 11:10 gives an empty array.

0
On

The short answer is yes, you can call a function inside a parfor.

The long answer is that parfor only works if each iteration inside the parfor is independent of the other iterations. Matlab has checks to catch when this isn't the case; though I don't know how full-proof they are. In your example, each foo() call can run independently and store its return value in a specific location of Mat that won't be written to or read by any other parfor iteration, so it should work.

This breaks down if values in Mat are being read by foo(). For example, if the parfor ran 4 iterations simultaneously, and inside each iteration, foo() was reading from Mat(1) and then writing a new value to Mat(1) that was based on what it read, the timing of the reads/writes would change the output values, and matlab should flag that.