多进程并行计算

想问一下,我在利用@distributed 对for循环进行多进程并行计算时,并行后的时间比未并行的时间还长,应该是没有并行成功。目前认为并行后时间变长了,是我想让程序并行,但没有并行成功,反而造成了多余的损耗。但现在我找不出没有并行成功的原因,所以想问一下。下面是一个示例代码,我的实际代码比较长,但主要就是用到了下面几个部分:

include("example.jl")
using .example
using Distributed
using SharedArrays
using LinearAlgebra

    df=[1   2   3   4   5   6   7   8   9  10  11  22  23  24  25  26  27  28  29  30  31  32   1  12;
        2   3   4   5   6   7   8   9  10  11  22  33  24  25  26  27  28  29  30  31  32  33  12  23;
        1   3   5   7   9  11  13  15  17  19  20  40  22  24  26  28  30  32  34  36  38  40   1  21;
        12  13  14  15  16  17  18  19  20  21  21  32  13  14  15  16  17  18  19  20  21  22   2  13]

    a,b,c,d=foo(df)
using Distributed
addprocs()

@everywhere module example
using Distributed
using SharedArrays
using LinearAlgebra

export foo

function foo(df)
    
    a=SharedArray{Int64,1}(size(df,2))
    b=SharedArray{Int64,1}(size(df,2))
    c=SharedArray{Int64,1}(size(df,2))
    d=SharedArray{Int64,1}(size(df,2))
   
    @inbounds @sync @distributed for i=1:size(df,2)

      a[i]=df[1,i]
      b[i]=df[2,i]
      c[i]=df[3,i]
      d[i]=df[4,i]
    end

    return a,b,c,d
end

end

可以考虑用更粗一点的并行粒度来降低开销,比如说将 size(df, 2) 个并行任务合并成 ceil(Int, size(df, 2)/block_size)

- for i = 1:size(df, 2)
+ for block_idx in 1:ceil(Int, size(df, 2)/block_size)
+     for column_idx in ...

感谢你的回复
你的意思是假如我的size(df,2)是100,可以将它两个任务合并成一个,变成50个任务再循环计算这样吗?

就是不要一列一列的循环,可以多列合并后循环

对,任务分解的时候粒度太细了会产生不必要的 overhead。

另外取决具体任务的计算模式以及 df 的大小,多进程的话每个进程里都会存储一份 df, a, b, c, d 的,这是一个非常大的内存开销。使用多线程模型的话可以允许共享内存,性能可能也会高一些。

1 个赞

好的,谢谢,我先再看一看
还想再问一下,一般利用多进程并行,并行时间比未并行时间更长的原因会有哪些呢?还是得看具体的代码才能知道?我是一个初学者,有没有什么初学者很容易忽视的问题

这个需要去看具体代码,而且与具体的计算设备的硬件模型有关。对于这种简单的并行模式的话 (embarrassingly parallel) 减少不必要的数据传输是最核心的性能优化方向(比如说,识别哪些数据会被复制到其他进程,并去除那些并不需要复制的数据)。

如果想要写出比较高效的并行计算的代码的话,最好去看一看相关的书了解一下并行计算的计算模式和硬件结构会比较有帮助一些。

1 个赞

好的,非常感谢!