【问题标题】:How to properly store variables to use with parfor?如何正确存储变量以与 parfor 一起使用?
【发布时间】:2020-01-24 14:57:56
【问题描述】:

我的计算基于二叉树,它采用变量块(称为程序集)的两个先前实例并生成另一个。 基于上分支的两个程序集生成一个新程序集,因此必须存储所有变量。

为此,我使用具有以下语法的元胞数组:Assembly_ij = Tree{ithBranch}{jthAssembly},其中Assembly18x3 double 矩阵。这种方法是 Matlab 的allowed,但是,它根本没有改进代码的执行。 我相信这是由于我将变量传递给工人的方式不恰当。我收到以下警告:

整个数组或结构“树”是一个广播变量。这 可能会导致不必要的通信开销。

大部分工作都在这部分代码中完成,它应该传达我正在犯的错误。

initialBranch = initialize();
Tree{1} = initialBranch;
for i = 2 : Nbranches
    branch = cell(1, elmsInBranch(i));
    parfor j = 1 : elmsInBranch(i)
        branch{j} = assembleBlocks(Tree{i-1}{2*j-1}, Tree{i-1}{2*j});
    end
    Tree{i} = branch;
end 

Matlab 必须将整个 Tree 结构传递给每个 worker,这是很多无用的复制。我不知道如何重写它以使其正常工作,但是,也许有一些聪明的方法可以为每个工人提取所需的变量

【问题讨论】:

  • 您是否尝试分配previous_branch = Tree{i-1},并在parfor 循环中使用该变量?
  • 即使 matlab 接受上述建模,它并没有真正使用您问题的局部性。假设你有 4 个工人。从第 3 级开始,每个工人可以在不与任何其他工人交谈的情况下完成树的 1/4。只有在最后,整棵树才必须放在一起。显然实施起来更具挑战性,但可能值得。

标签: matlab parallel-processing


【解决方案1】:

问题是您将整个Tree{i-1} 变量传递到parfor 循环的每个(并行)迭代中。这是因为 MATLAB 解释器不够“聪明”,无法确定您需要 Tree{i-1} 的哪些部分,因为您正在通过基于 j 的一些计算来动态索引它。

在外部循环中分配一个临时变量,可以在内部循环中直接用j 进行索引,应该可以解决这个问题:

initialBranch = initialize();
Tree{1} = initialBranch;
for i = 2 : Nbranches
    N = elmsInBranch(i);
    branch = cell(1, N);
    % Pre-partition the data to send individual packets to each node 
    iTrees = arrayfun( @(j) Tree{i-1}([2*j-1,2*j]), 1:N, 'uni', 0 );
    % Parallel loop...
    parfor j = 1 : N
        jTrees = iTrees{j}; % direct indexing using 'j', no calculation      
        branch{j} = assembleBlocks(jTrees{1}, jTrees{2});
    end
    Tree{i} = branch;
end

请注意,cellfun 我添加了对您的数据进行分区,以便每个并行节点一次可以直接索引一个元素,其中包含循环中所需的两个 Tree 项目。这可能会导致内存重复,但比将整个数组广播到每个节点的重复要少!

【讨论】:

  • 不错的解决方案! iTrees 的本地副本是一个元胞数组,它只会指向与 Tree 中相同的数据矩阵,因此不会占用过多的内存。
  • @Cris 但是它们不能在内部通过引用存储,因为对iTrees 的更改不会影响Tree?并且每个节点都“发送”了自己的元素......或者是根据需要分配的?
  • MATLAB 会进行惰性复制,我相信您知道。这意味着b=a 不会复制a,直到您修改两个变量之一。 iTrees 中的数组将指向与Tree 中的数组相同的数据,直到被修改为止。
  • 感谢您的回答!我知道这应该如何工作,但是,代码在cellfun 行崩溃。我得到Input #2 expected to be a cell array, was double. 我只是使用匿名函数:iTrees = @(j) AsmTree{i-1}([2*j-1,2*j])。这使得警告消失了,但是,速度的提高并不令人满意:(顺序程序在 0.9 秒内评估,而对于我的初始方法,它花了整整 9 秒。现在,通过您的修复,大约需要 6 秒。跨度>
  • @Maverick 对不起,那应该是arrayfun - 我已经编辑了我的答案。值得注意的是,0.9 秒的执行时间并不长,与并行工作人员通信总会有开销,如果你看到减少到 0.9 秒以下,我会有点惊讶。通常,关键是进一步优化您的代码,而不是向它扔parfor
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2013-10-04
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
  • 2021-06-03
相关资源
最近更新 更多