嵌套的parfor
而且为
循环和其他parfor
需求
嵌套的parfor
循环
您不能使用parfor
循环在另一个parfor
循环。作为一个例子,下面的嵌套parfor
-loops是不允许的:
parfori = 1:10parforj = 1:5...结束结束
提示
你不能嵌套parfor
直接在另一个parfor
循环。一个parfor
-loop可以调用包含parfor
-循环,但不会获得任何额外的并行性。
代码分析器在MATLAB®的编辑器标记使用parfor
在另一个parfor
循环:
你不能嵌套parfor
-循环,因为并行化只能在一个级别上执行。因此,选择并行运行哪个循环,并将另一个循环转换为a为
循环。
在处理嵌套循环时,考虑以下性能问题:
并行处理会产生开销。通常,应该并行运行外部循环,因为开销只发生一次。如果你并行运行内部循环,那么每一个
parfor
执行会产生开销。看到将嵌套的for循环转换为parfor循环举个例子,如何测量并行开销。确保迭代的数量超过工作人员的数量。否则,就不会使用所有可用的工作者。
试着平衡
parfor
循环迭代时间。parfor
试图弥补一些负载不平衡。
提示
总是并行运行最外面的循环,因为可以减少并行开销。
您还可以使用一个函数parfor
把它嵌入parfor
循环。并行化只发生在外部级别。在下面的例子中,调用一个函数MyFun.m
在外面parfor
循环。内parfor
循环嵌入MyFun.m
顺序运行,而不是并行运行。
parfori = 1:10 MyFun(i)结束函数MyFun(我)parforj = 1:5...结束结束
提示
嵌套的parfor
-循环通常不会给你计算上的好处。
将嵌套为
循环,parfor
循环
嵌套循环的典型用法是使用单循环变量索引一个维度,使用嵌套循环变量索引另一个维度,逐步遍历数组。基本形式是:
X = 0 (n, m);为一个= 1:n为b = 1:m X(a,b) = fun(a,b)结束结束
下面的代码显示了一个简单的示例。使用抽搐
而且toc
来测量所需的计算时间。
一个= 100;抽搐为i = 1:10 0为j = 1:100 a(i,j) = max(abs(eig(rand(a))));结束结束toc
运行时间为49.376732秒。
可以并行两个嵌套循环中的任何一个,但不能并行运行两个循环。原因是并行池中的工作人员不能启动或访问进一步的并行池。
如果循环计数我
转换为parfor
方法来执行嵌套循环,那么池中的每个worker都使用j
循环计数器。的j
循环本身不能作为parfor
在每一个工人。
因为并行处理会产生开销,所以必须仔细选择是要转换内部还是外部为
循环,parfor
循环。下面的示例展示了如何测量并行开销。
首先只转换外为
循环,parfor
循环。使用抽搐
而且toc
来测量所需的计算时间。使用ticBytes
而且tocBytes
测量并行池中的工作者之间的数据传输量。
运行新代码,然后再运行一次。第一次运行比后续的运行慢,因为并行池需要一些时间来启动并使代码对工作者可用。
一个= 100;抽搐ticBytes (gcp);parfori = 1:10 0为j = 1:100 a(i,j) = max(abs(eig(rand(a))));结束结束tocBytes toc (gcp)
bytesessenttoworkers BytesReceivedFromWorkers __________________ ________________________ 1 32984 24512 2 33784 25312 3 33784 25312 4 34584 26112 Total 1.3514e+05 1.0125e+05 Elapsed time is 14.130674 seconds。
然后只转换内心的循环parfor
循环。与前面的情况一样,测量所需的时间和传输的数据。
一个= 100;抽搐ticBytes (gcp);为i = 1:10 0parforj = 1:100 a(i,j) = max(abs(eig(rand(a))));结束结束tocBytes toc (gcp)
bytesessenttoworkers BytesReceivedFromWorkers __________________ ________________________ 1 1.3496e+06 5.487e+05 2 1.3496e+06 5.4858e+05 3 1.3677e+06 5.6034e+05 4 1.3476e+06 5.4717e+05 Total 5.4144e+06 2.2048e+06流逝时间为48.631737秒。
如果您将内心的循环parfor
-循环时,传输的时间和数据量都比并行的外循环大得多。在这种情况下,运行时间几乎与在嵌套的情况下相同为
循环的例子。这种加速比并行运行外部循环要小,因为您需要更多的数据传输,因此并行开销也会更多。因此,如果您执行内心的并行循环与串行运行相比,在计算上没有任何好处为
循环。
如果您想减少并行开销并加快计算速度,请并行运行外部循环。
如果您将内心的循环,然后外部循环的每次迭代开始一个单独的parfor
循环。也就是说,内部循环转换创建100parfor
循环。每一个倍数parfor
死刑会增加开销。如果您想减少并行开销,您应该并行运行外部循环,因为开销只发生一次。
提示
如果您想加快代码的速度,请始终并行地运行外部循环,因为这样可以减少并行开销。
嵌套的为
-循环:要求和限制
如果你想转换一个嵌套的为
循环,parfor
-loop,你必须确保你的循环变量被正确分类,参见解决parfor-Loops中的变量问题.如果您的代码不遵守标记为的指导方针和限制要求,就会得到一个错误。MATLAB在读取代码时捕获其中一些错误。这些错误被标记为要求(静态).
要求(静态):必须定义a的取值范围为 嵌套在a中的循环parfor -循环通过常量或广播变量。 |
在下面的示例中,左边的代码无法工作,因为您定义了为
-loop通过函数调用。右边的代码提供了一种解决方法,它首先在parfor
循环:
无效的 | 有效的 |
---|---|
A = 0 (100, 200);parfori = 1:size(A, 1)为1:size(A, 2) A(i, j) = i + j;结束结束 |
A = 0 (100, 200);n = size(A, 2);parfori = 1:尺寸(1)为1:n A(i, j) = i + j;结束结束 |
要求(静态):嵌套的索引变量为 -loop决不能显式赋值,除非通过its为 声明。 |
必须遵守此限制。如果嵌套为
-loop变量在aparfor
-除its之外的其他循环为
方法索引的区域为
-loop变量不能保证在每个worker上都可用。
左边的代码是无效的,因为它试图修改嵌套的值为
循环变量j
在循环体中。右边的代码通过分配嵌套提供了一种解决方法为
-loop变量转换为临时变量t
,然后更新t
.
无效的 | 有效的 |
---|---|
一个= 0 (10);parfori = 1:10为A(i, j) = 1;j = + 1;结束结束 |
一个= 0 (10);parfori = 1:10为A(i, j) = 1;t = j;T = T + 1;结束结束 |
要求(静态):你不能索引或下标嵌套为 循环变量。 |
必须遵守此限制。如果一个嵌套的为
-loop变量被索引,迭代不保证是独立的。
左边的示例无效,因为它试图索引嵌套的对象为
循环变量j
.右边的示例删除了这个索引。
无效的 | 有效的 |
---|---|
一个= 0 (10);parfori = 1:10为J = 1:10 J (1);结束结束 |
一个= 0 (10);parfori = 1:10为J = 1:10 J;结束结束 |
要求(静态):使用嵌套时为 -loop变量用于索引切片数组时,必须以普通形式使用该变量,而不是作为表达式的一部分。 |
例如,下面左边的代码不能工作,但是右边的代码可以:
无效的 | 有效的 |
---|---|
A = 0 (4,11);parfori = 1:4为j = 1:10 A(i, j + 1) = i + j;结束结束 |
A = 0 (4,11);parfori = 1:4为j = 2:11 A(i, j) = i + j - 1;结束结束 |
要求(静态):如果使用嵌套为 类的其他地方不能使用该数组parfor 循环。 |
在下面的示例中,左边的代码不能工作,因为一个
是否在嵌套内进行切片和索引为
循环。右边的代码有用是因为v
被分配给一个
在嵌套循环之外:
无效的 | 有效的 |
---|---|
A = 0 (4,10);parfori = 1:4为j = 1:10 A(i, j) = i + j;结束disp ((i, j))结束 |
A = 0 (4,10);parforI = 1:4 v = 0 (1,10);为J = 1:10 v(J) = I + J;结束disp(v(j)) A(i,:) = v;结束 |
parfor
循环的限制
嵌套函数
的身体parfor
-loop不能引用嵌套函数。但是,它可以通过函数句柄调用嵌套函数。试试下面的例子。请注意,(idx) = nfcn (idx)
在parfor
-loop不起作用。你必须使用函数宏指令
来调用fcn
处理的parfor
循环体。
函数一个= pfeg函数Out = nfcn(in) Out = 1 + in;结束fcn = @nfcn;parforidx = 1:10 A(idx) = feval(fcn, idx);结束结束
>> pfeg启动并行池(parpool)使用'Processes'配置文件…连接4个工人。Ans = 2 3 4 5 6 7 8 9 10 11
提示
类中引用嵌套函数的函数句柄parfor
-loop,则外部作用域变量的值在worker之间不同步。
嵌套的parfor
循环
的身体parfor
-loop不能包含parfor
循环。有关更多信息,请参见嵌套parfor-Loops.
嵌套的spmd
语句
的身体parfor
-loop不能包含spmd
声明中,和一个spmd
语句不能包含parfor
循环。原因是工作程序不能启动或访问更多的并行池。
打破
而且返回
语句
的身体parfor
循环不能包含打破
或返回
语句。考虑parfeval
或parfevalOnAll
相反,因为你可以使用取消
在他们身上。
全局变量和持久变量
的身体parfor
循环不能包含全球
或持续的
变量声明。原因是这些变量在工作人员之间是不同步的。您可以使用全球
或持续的
函数中的变量,但它们的值只对创建它们的工作者可见。而不是全球
在变量中,使用函数实参共享值是更好的实践。
要了解更多关于可变需求的信息,请参见解决parfor-Loops中的变量问题.
脚本
如果脚本引入了一个变量,则不能从parfor
循环或spmd
声明。原因是这个脚本会导致透明度违反。有关更多细节,请参见确保parfor-Loops或spmd语句的透明度.
匿名函数
类的对象内部可以定义匿名函数parfor
循环。但是,不支持匿名函数中的切片输出变量。您可以通过为切片变量使用临时变量来解决这个问题,如下面的示例所示。
x = 1:10;parforI =1:10 temp = x(I);anonymousFunction = @() 2*temp;x(i) = anonymousFunction() + i;结束disp (x);
有关切片变量的更多信息,请参见切变量.
inputname
功能
使用inputname
内部不支持返回与参数号对应的工作空间变量名parfor
循环。原因是parfor
工作人员不能访问MATLAB桌面的工作空间。要解决这个问题,请打电话inputname
之前parfor
,如下例所示。
一个=“一个”;myFunction (a)函数X = myFunction(a) name = inputname(1);parfori=1:2 X(i).(name) = i;结束结束
负载
功能
的语法负载
内部不支持不赋值给输出结构的值parfor
循环。内部parfor
,总是指定的输出负载
一个结构。
输入参数个数
或nargout
功能
内部不支持以下用途parfor
循环:
使用
输入参数个数
或nargout
没有函数参数使用
narginchk
或nargoutchk
验证当前正在执行的函数调用中的输入或输出参数的数量
原因是工作人员不能访问MATLAB桌面的工作空间。要解决这个问题,请在前面调用这些函数parfor
,如下例所示。
myFunction (“一个”,“b”)函数X = myFunction(a,b) nin = nargin;parfori=1:2 X(i) = i*nin;结束结束
- code脚本
你可以调用p代码脚本文件parfor
-循环,但P-code脚本不能包含parfor
循环。要解决这个问题,可以使用P-code函数而不是P-code脚本。