一个并行思路的实现

目的:

我希望通过多核并行,对一个共享数组中固定位置进行赋值

例子:

现在有A,B,C三个矩阵,都是(3X3),通过对A,B,C每一行元素的迭代,可以得到一个新的矩阵d,它的大小为(2X2),然后将这4个元素按顺序放到共享数组S(这个例子中S为12X1)中指定的位置:

A=\left[ \begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{matrix} \right] , B=\left[ \begin{matrix} 2 & 3 & 1 \\ 4 & 5 & 6 \\ 8 & 9 & 7 \\ \end{matrix} \right] , C=\left[ \begin{matrix} 1 & 3 & 6 \\ 4 & 7 & 7 \\ 2& 3 & 1 \\ \end{matrix} \right]

A,B,C的第一行进行简单计算,得到d

d=\left[ \begin{matrix} 6 & 2 \\ 1 & 3 \\ \end{matrix} \right]

这时将他填充到S中:

S=\left[ \begin{matrix} 6 \\ 2 \\ 1 \\ 3 \\ ... \\ \end{matrix} \right]

因为这是取自A,B,C每个矩阵的第一行,所以他属于S的前四个位置,当取A,B,C每个矩阵的第二行元素进行计算时,得到的(4X4)的d矩阵就应该放在S的第5~8位置。

代码:

如上,每次迭代之间是没有影响的,所以我认为是可以并行的,代码大概应该是这样的结构:

function test(A,B,C)
    S = SharedArray{Float64,1}(size(A,1)*4)
    #A,B,C有多少行,就会生成多少个d,每个d需要S中的4个位置

    @sync @distributed for i = 1:size(A,1)
        d =  ...
        #这里对A,B,C的第i行进行一些简单计算,得到d
        
        xi = i*4-3

        for n1 = 1:2
           for n2 = 1:2
               S[xi] = d[n1,n2]
               xi = xi+1
           end
        end

    end

end

请问这种方式来实现并行计算有什么问题吗,我在实际操作中并行的效果并不理想:sweat_smile:

  1. 如之前的帖子里所说,建议用多线程

先定义一个你上面提到的简单计算的函数:

function f(a, b, c, s)
    # a, b, c, s 分别对应 A, B, C, S的一个slice view
end

然后直接调用Threads.@threads

  1. 或者,如果你执意要用SharedArray和多进程(单从你上面的描述看不出有这个必要)。

@distributedpmap都可以,前者会把所有的计算根据worker自动切片后分配到每个进程:

后者则需要你自己确定每个进程上处理的索引。

理论上讲,对你这个任务而言,@distributedpmap二者的差别应该不大,但是,需要注意,这里A, B, C, S 都要设置为SharedArray,不然就会产生拷贝。

十分感谢,我试了一下,问题解决了!CPU使用率100%,时间减少了很多!问题出在将A,B,C,S都设置成SharedArray,我之前只是将S设置成SharedArray。
这里我还想提个问题:
如何判断我当前的任务是用多线程并行还是多进程并行?
我上面例子中简单计算的那个函数其实也挺麻烦,循环次数也很多,什么样的计算适合多进程并行呢?
(之后我也把我这个例子改成多线程的,然后测试一下时间)

这个得你自己根据实际任务做比较了。我也没太有经验…

好的,多谢:grinning:

如果使用多线程,是不需要使用SharedArray的。SharedArray是在不同的进程中共享数据,而多线程数据本身就是共享的。
Q:如何判断多线程还是多进程?
A:使用Threads相关的就是多线程,使用Distributed就是多进程。
Q:什么样的任务适合多进程?
A:数据量极大,数据依赖低,适用于MapReduce模式的计算,使用多进程计算有优势。
Q:什么样的任务适合多线程?
A:数据强依赖,小任务,调用频繁的任务适用于多线程。

非常感谢,我的例子数据量确实很大,而且是MapReduce模式的计算(我理解就是程序将每个任务分配出去,每个任务执行的计算都是一样的,最后再将得到的结果进行汇总)

但我不太理解“调用频繁的任务”是什么意思?:sweat_smile:

举个例子,你如果写一个网络服务,每个client来你都会返回一个html。这种需要响应快,调用频繁就适合线程,而且开一个线程开销很小。