在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.
我做错了什么?
来自parfor
:上的文档
parfor循环的主体不能包含全局或持久变量声明。
在问题的上下文中,即调用parfor
中的函数,而该函数又引用了global
,这转化为:"parfor
可能不会给出预期或有意义的结果"。
这很有道理。考虑以下
Lab 1: Lab 2:
GetB(); GetB();
如果GetB()
的内容是:
function GetB()
global B;
%# do something useful
B = rand;
end
当B
在Lab 1
上被引用时,它的值是多少?以及在CCD_ 10上?rand
的不同结果是如何传达的?会一团糟的!
编写适合parfor
循环的代码可能是一件非常痛苦的事情,因为这些代码来自于只考虑正常for
循环的东西。一般来说,当你事先知道你要写一段计算密集型的Matlab代码时,从一开始就把所有函数和循环写成parfor
循环。这是唯一的方法,这样的错误不会花费你一天的代码转换你的函数。
从for
转换为parfor
是一点也不琐碎。
GLOBAL
数据很难在PARFOR
中使用,因为每个工作程序都是一个单独的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
我个人会尝试从您的应用程序中删除GLOBAL
数据——这将使它更好地与PARFOR
配合使用,并使依赖关系更加清晰。
另一个需要探索的选项是我的Worker Object Wrapper,它旨在防止您不得不多次向Worker传输数据。你可以这样使用它:
options = buildOptions();
w_options = WorkerObjWrapper(options);
parfor ii=1:N
result(ii) = myFcnNeedingOptions(ii, w_options.Value);
end