为什么在parfor中访问2d矩阵这么慢?

时间:2018-08-08 22:42:26

标签: matlab performance parfor

假设我有一个大矩阵A:

A = rand(10000,10000);

以下序列号大约花费了0.5秒

tic
for i=1:5
    r=9999*rand(1);
    disp(A(round(r)+1, round(r)+1))
end
toc

以下带有parfor的代码花费了大约47秒

tic
parfor i=1:5
    r=9999*rand(1);
    disp(A(round(r)+1, round(r)+1))
end
toc

如何加快parfor代码的速度?

编辑:如果我不使用disp,而是尝试使用以下代码计算总和

sum=0;
tic
for i=1:5000
   r=9999*rand(1);
   sum=sum+(A(round(r)+1, round(r)+1));
end
toc

这需要.025秒

但是parfor花费42.5秒:

tic
parfor i=1:5000
   r=9999*rand(1);
   sum=sum+(A(round(r)+1, round(r)+1));
end
toc

3 个答案:

答案 0 :(得分:5)

您的问题是不考虑节点通信开销。

当您使用parfor循环使用并行计算时,您必须考虑几个为客户端节点执行小任务的工作节点的结构。

以下是您提出的测试问题:

  • 函数disp是串行的,因为您一次只能向客户端节点显示一个结果。调度任务需要节点之间的通信。

  • 在循环外部创建求和意味着所有节点都必须将当前值传递回客户端节点。

  • 在所有示例中,
  • Abroadcast variable。从文档中:

      

    这种类型的变量对于特定任务可能非常有用,甚至必不可少。但是,较大的广播变量会导致客户端与工作人员之间的大量交流,并增加并行开销

    MATLAB编辑器会警告您这一点,并使用以下工具提示在橙色变量下划线:

      

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


相反,我们可以预先计算一些随机索引,并将A切片为临时变量以在循环中使用。然后在循环之后进行收集操作(例如将所有部分加起来)。

k = 50;
sumA = zeros( k, 1 );         % Output values for each loop index
idx = randi( [1,1e4], k, 1 ); % Calculate our indices outside the loop
randA = A( idx, idx );        % Slice A outside the loop
parfor ii = 1:k
    sumA( ii ) = randA( ii ); % All that's left to do in the loop
end
sumA = sum( sumA );           % Collate results from all nodes

我做了一个快速基准测试,使用R2017b和12名工人将您的2个总和测试与上述代码进行比较,这是我的结果:

               Serial loop: ~ 0.001 secs      
Parallel with broadcasting: ~ 100   secs
  Parallel no broadcasting: ~ 0.1   secs

此操作的并行循环过大,开销没有道理,但是很明显,通过一些预分配和避免广播变量,它们至少慢了5个数量级!

看看没有广播变量的代码版本如何也使用更多的向量化,这将加快代码的使用速度,而不必使用parfor。在使用并行计算之前优化代码不仅可以加快串行计算的速度,而且通常也使转换更加容易!


旁注:sumi是错误的变量名,因为它们是内置函数的名称。

答案 1 :(得分:0)

如果第一次循环需要0.5秒,则您的计算机速度非常慢,或者计时错误。

当您在命令行(或脚本)中键入代码时,解释器将在执行代码时对其进行解释,有时甚至在循环部分中也将解释该代码。

相反,如果您编写一个函数,则代码将在加载到内存后由JIT编译,并且每次都会快速执行。

如果将此循环放到函数中,您会发现计时显着改善。

现在,您将需要花费一秒钟的时间进行计时。使用tic,toc测量的时间不是很精确。这种方法可以比较一分钟与三分钟,或者1秒与5秒的比较,但是在这种情况下,时间太短,可能会受到计算机上运行的其他各种因素的影响。请改用timeit。它将多次运行该函数,并为您提供平均运行时间的良好估计。

答案 2 :(得分:-1)

所以有几个主要原因,

  1. MATLAB并行工具箱很烂。除非您使用的是GPU部分,否则它只会起作用。
  2. 唯一有益的情况是各个任务足够大。您的计算机必须专用于一个核心,以将作业分配给所有其他核心。除非作业的大小足够大,否则这很昂贵并且开销很大。您的计算机正在超时运行,分配少量作业。如果您要分配的工作每个都需要一分钟,那将是另一回事。
  3. 您执行的工作太少。在非常小的工作上,您只循环5次。您为何还要尝试多线程处理呢?当我将其分配为循环500,000次时,如果我将矩阵大小减小为1000 x 1000,则最终会获得parfor的加速
  4. 运行parfor时,MATLAB必须在所有胎面上复制内存,您有一个10,000 x 10,000的矩阵,占用800 MB。在4核计算机上复制的内容为3,200 MB,或可能是您的一半RAM。在这些阵列上进行操作会占用额外的内存,从而可能使大小增加一倍-> 6,400 MB。可能超出您的承受能力。

简单地说,“我如何加快这个parfor代码的速度?”

你不