全局和parfor

ola*_*ndo 6 parallel-processing matlab global-variables parfor

parfor循环内部,我试图调用一个global无法访问的函数.

功能

function a = getA()
   global OPTIONS;
   a=OPTIONS.PROBLEM.A;
end
Run Code Online (Sandbox Code Playgroud)

循环:

parfor i=1:3
    b=getA();
end
Run Code Online (Sandbox Code Playgroud)

错误:

Error using parallel_function (line 589)

Attempt to reference field of non-structure array.
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Rod*_*uis 8

文档parfor:

parfor-loop的主体不能包含全局或持久变量声明.

在您的问题的上下文中,即调用其中的函数parfor依次引用a global,这转换为:" parfor可能不会给出预期的或有意义的结果".

这很有道理.考虑以下

Lab 1:         Lab 2: 

GetB();        GetB();
Run Code Online (Sandbox Code Playgroud)

如果内容GetB()是这样的:

function GetB()
    global B;

    %# do something useful

    B = rand;

 end
Run Code Online (Sandbox Code Playgroud)

B它被引用时的价值是Lab 1多少?并在Lab 2rand传达的不同结果如何?这将是一团糟!

编写适合parfor循环的代码可能是一个真正的痛苦,当代码来自只for考虑正常的循环的东西.通常,当您事先知道要编写计算密集的Matlab代码时,请parfor从头开始将所有函数和循环编写为循环.这是像这样的错误的唯一方法,不会花费你一天的代码转换你的功能.

从转换forparfor不是在所有琐碎.

  • @noam见最后编辑.对此最简单的解决方法是取消全局`global`并将其作为参数传递给需要它的所有函数. (2认同)

Edr*_*ric 6

GLOBAL数据很难在内部使用,PARFOR因为每个worker都是一个单独的MATLAB进程,并且全局变量不会从客户端(或任何其他进程)同步到worker.如果您从工作者的单独函数初始化全局数据,它将起作用.(正如Rody指出的那样,不允许直接在PARFOR循环体中使用global关键字- 但是,单独的函数可以这样做).所以,这样做是合法的:

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

我个人会尝试GLOBAL从您的应用程序中删除数据 - 它将使其更好地工作PARFOR,它将使依赖关系更清晰.

另一个探索的选择是我的工作对象包装器,它旨在阻止您多次向工作人员传输数据.您可以这样使用它:

options = buildOptions();
w_options = WorkerObjWrapper(options);
parfor ii=1:N
  result(ii) = myFcnNeedingOptions(ii, w_options.Value);
end
Run Code Online (Sandbox Code Playgroud)