8

parfor是在多个“工作人员”之间分配密集计算的独立迭代的便捷方式。一个有意义的限制是parfor-loops 不能嵌套,并且始终是对therethere等类似问题的答案。

为什么跨循环边界的并行化如此可取

考虑以下代码,其中迭代在允许 4 个工作人员的机器上花费高度可变的时间。两个循环都迭代了 6 个值,显然很难在 4 个值之间共享。

for row = 1:6
    parfor col = 1:6
        somefun(row, col);
    end
end

选择内部循环似乎是一个好主意,parfor因为单个调用somefun比外部循环的迭代更具可变性。但是,如果每次调用的运行时间somefun都非常相似怎么办?如果运行时有趋势并且我们有三个嵌套循环怎么办?这些问题经常出现,人们走极端

组合循环所需的模式

理想情况下,somefun为所有对运行rowand col,并且无论 iterand 正在变化,工作人员都应该忙起来。解决方案应该看起来像

parfor p = allpairs(1:6, 1:6)
    somefun(p(1), p(2));
end

不幸的是,即使我知道哪个内置函数创建了一个包含 和 的所有组合的矩阵rowcolMATLAB 也会报错Parfor 语句的范围必须是行向量。然而,for不会抱怨并很好地迭代列。一个简单的解决方法是创建该矩阵,然后使用以下命令对其进行索引parfor

p = allpairs(1:6, 1:6);
parfor k = 1:size(pairs, 2)
    row = p(k, 1);
    col = p(k, 2);
    somefun(row, col);
end

代替allpairs我正在寻找的内置函数是什么?有人想出了一个方便的惯用模式吗?

4

3 回答 3

10

MrAzzman 已经指出了如何线性化嵌套循环。这是线性化 n 个嵌套循环的通用解决方案。

1)假设您有一个简单的嵌套循环结构,如下所示:

%dummy function for demonstration purposes
f=@(a,b,c)([a,b,c]);

%three loops
X=cell(4,5,6);
for a=1:size(X,1);
    for b=1:size(X,2);
        for c=1:size(X,3);
            X{a,b,c}=f(a,b,c);
        end
    end
end

2)使用for循环的基本线性化:

%linearized conventional loop
X=cell(4,5,6);
iterations=size(X);
for ix=1:prod(iterations)
    [a,b,c]=ind2sub(iterations,ix);
    X{a,b,c}=f(a,b,c);
end   

3) 使用 parfor 循环进行线性化。

%linearized parfor loop
X=cell(4,5,6);
iterations=size(X);
parfor ix=1:prod(iterations)
    [a,b,c]=ind2sub(iterations,ix);
    X{ix}=f(a,b,c);
end

4) 使用带有传统 for 循环的第二个版本,执行迭代的顺序被改变。如果有任何依赖于此,您必须颠倒索引的顺序。

%linearized conventional loop
X=cell(4,5,6);
iterations=fliplr(size(X));
for ix=1:prod(iterations)
    [c,b,a]=ind2sub(iterations,ix);
    X{a,b,c}=f(a,b,c);
end

使用parfor循环时颠倒顺序是无关紧要的。您根本不能依赖执行顺序。如果您认为它有所作为,则不能使用parfor.

于 2013-11-30T02:05:56.140 回答
5

您应该可以使用bsxfun. 我相信bsxfun将在可能的情况下并行化代码(有关更多信息,请参见此处),在这种情况下,您应该能够执行以下操作:

bsxfun(@somefun,(1:6)',1:6);

不过,您可能希望对此进行基准测试。

或者,您可以执行以下操作:

function parfor_allpairs(fun, num_rows, num_cols)

parfor i=1:(num_rows*num_cols)
    fun(mod(i-1,num_rows)+1,floor(i/num_cols)+1);
end

然后调用:

parfor_allpairs(@somefun,6,6);
于 2013-11-30T01:49:10.057 回答
2

根据@DanielR@MrAzzaman的回答,我发布了两个函数,如果它们不是从一个开始iterlin,则iterget代替prodandind2sub允许迭代范围。该模式的一个示例变为

rng = [1, 4; 2, 7; 3, 10];
parfor k = iterlin(rng)
    [plate, row, col] = iterget(rng, k);
    % time-consuming computations here %
end

该脚本将处理板 1 到 4 上第 2 到 7 行和第 3 到 10 列中的孔,而没有任何工人空闲,同时等待处理更多孔。希望这对某人有所帮助,我将其存放iterlinitergetMATLAB File Exchange中。

于 2013-12-01T23:00:12.010 回答