Pregunta

Inside a parfor loop, I am trying to call a function that accesses a global to no avail.

The function

function a = getA()
   global OPTIONS;
   a=OPTIONS.PROBLEM.A;
end

The loop:

parfor i=1:3
    b=getA();
end

The error:

Error using parallel_function (line 589)

Attempt to reference field of non-structure array.

What am I doing wrong?

¿Fue útil?

Solución

From the documentation on parfor:

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

In the context of your problem, i.e., calling a function within the parfor that in turn references a global, this translates into: "parfor will probably not give expected or meaningful results".

This makes perfect sense. Consider the following

Lab 1:         Lab 2: 

GetB();        GetB();

if the contents of GetB() is this:

function GetB()
    global B;

    %# do something useful

    B = rand;

 end

what will the value of B be when it is referenced on Lab 1? and on Lab 2? How are the different outcomes of rand communicated? It's going to be a mess!

Writing code suited for parfor loops can be a real pain when that code comes from something that only had normal for-loops in mind. Generally, when you know beforehand you're going to write a computationally intensive piece of Matlab code, write all functions and loops as parfor loops right from the beginning. That is the only way that bugs like these will not cost you a day on transcoding your functions.

Converting from for to parfor is not at all trivial.

Otros consejos

GLOBAL data is hard to use inside PARFOR because each worker is a separate MATLAB process, and global variables are not synchronised from the client (or any other process) to the workers. It would work if you initialized the global data from a separate function on the workers. (As Rody points out, using the global keyword directly in the body of a PARFOR loop is not allowed - however, separate functions can do this). So, it would be legal to do this:

parfor ii=1:matlabpool('size')
  myFcnWhichSetsUpGlobalData(); %# defines global OPTIONS
end
parfor ii=1:N
  result(ii) = myFcnWhichUsesGlobalData(); %# reads global OPTIONS
end

I would personally attempt to remove GLOBAL data from your application - it will make it work better with PARFOR, and it will make dependencies clearer.

One further option to explore is my Worker Object Wrapper which is designed to stop you having to transfer data to the workers multiple times. You might use it this way:

options = buildOptions();
w_options = WorkerObjWrapper(options);
parfor ii=1:N
  result(ii) = myFcnNeedingOptions(ii, w_options.Value);
end
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top