在parfor
循环中,我试图调用访问global
的函数无效。
功能
function a = getA()
global OPTIONS;
a=OPTIONS.PROBLEM.A;
end
循环:
parfor i=1:3
b=getA();
end
错误:
Error using parallel_function (line 589)
Attempt to reference field of non-structure array.
我做错了什么?
答案 0 :(得分:8)
来自parfor
上的documentation:
parfor-loop的主体不能包含全局或持久变量声明。
在您的问题的上下文中,即调用parfor
中的一个函数,该函数反过来引用global
,这转换为:“parfor
可能不会给出预期的或有意义的结果”。
这很有道理。请考虑以下
Lab 1: Lab 2:
GetB(); GetB();
如果GetB()
的内容是这样的话:
function GetB()
global B;
%# do something useful
B = rand;
end
B
上引用Lab 1
时的价值是多少?并在Lab 2
? rand
的不同结果如何传达?这将是一团糟!
编写适合parfor
循环的代码可能是一个真正的痛苦,当代码来自于只有正常for
- 循环的东西时。通常,当您事先知道要编写计算密集的Matlab代码时,请从头开始将所有函数和循环编写为parfor
循环。这是像这样的错误的唯一方法,不会花费你一天的代码转换你的功能。
从for
转换为parfor
并非完全无关紧要。
答案 1 :(得分:6)
GLOBAL
数据在PARFOR
内很难使用,因为每个工作程序都是一个单独的MATLAB进程,并且全局变量不会从客户端(或任何其他进程)同步到工作程序。如果您从工作者的单独函数初始化全局数据,它将起作用。 (正如Rody指出的那样,不允许直接在PARFOR循环体中使用global
关键字 - 但是,单独的函数可以执行此操作)。因此,这样做是合法的:
parfor ii=1:matlabpool('size')
myFcnWhichSetsUpGlobalData(); %# defines global OPTIONS
end
parfor ii=1:N
result(ii) = myFcnWhichUsesGlobalData(); %# reads global OPTIONS
end
我个人会尝试从您的应用中删除GLOBAL
数据 - 它会使PARFOR
更好地工作,并且会使依赖关系更加清晰。
另一个探索的选择是我的Worker Object Wrapper,它旨在阻止您多次向工作人员传输数据。您可以这样使用它:
options = buildOptions();
w_options = WorkerObjWrapper(options);
parfor ii=1:N
result(ii) = myFcnNeedingOptions(ii, w_options.Value);
end