目的:
我希望通过多核并行,对一个共享数组中固定位置进行赋值
例子:
现在有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
请问这种方式来实现并行计算有什么问题吗,我在实际操作中并行的效果并不理想
Jun
2019 年7 月 14 日 06:49
2
如之前的帖子里所说,建议用多线程
这种问题用多线程就可以,开销会比多进程小的多
先定义一个你上面提到的简单计算的函数:
function f(a, b, c, s)
# a, b, c, s 分别对应 A, B, C, S的一个slice view
end
然后直接调用Threads.@threads
。
或者,如果你执意要用SharedArray
和多进程(单从你上面的描述看不出有这个必要)。
用@distributed
和pmap
都可以,前者会把所有的计算根据worker自动切片后分配到每个进程:
function pfor(f, R)
@async @sync for c in splitrange(length(R), nworkers())
@spawn f(R, first(c), last(c))
end
end
后者则需要你自己确定每个进程上处理的索引。
理论上讲,对你这个任务而言,@distributed
和pmap
二者的差别应该不大,但是,需要注意,这里A, B, C, S
都要设置为SharedArray
,不然就会产生拷贝。
十分感谢,我试了一下,问题解决了!CPU使用率100%,时间减少了很多!问题出在将A,B,C,S都设置成SharedArray,我之前只是将S设置成SharedArray。
这里我还想提个问题:
如何判断我当前的任务是用多线程并行还是多进程并行?
我上面例子中简单计算的那个函数其实也挺麻烦,循环次数也很多,什么样的计算适合多进程并行呢?
(之后我也把我这个例子改成多线程的,然后测试一下时间)
Jun
2019 年7 月 14 日 07:34
4
这个得你自己根据实际任务做比较了。我也没太有经验…
如果使用多线程,是不需要使用SharedArray的。SharedArray是在不同的进程中共享数据,而多线程数据本身就是共享的。
Q:如何判断多线程还是多进程?
A:使用Threads相关的就是多线程,使用Distributed就是多进程。
Q:什么样的任务适合多进程?
A:数据量极大,数据依赖低,适用于MapReduce模式的计算,使用多进程计算有优势。
Q:什么样的任务适合多线程?
A:数据强依赖,小任务,调用频繁的任务适用于多线程。
非常感谢,我的例子数据量确实很大,而且是MapReduce模式的计算(我理解就是程序将每个任务分配出去,每个任务执行的计算都是一样的,最后再将得到的结果进行汇总)
但我不太理解“调用频繁的任务”是什么意思?
举个例子,你如果写一个网络服务,每个client来你都会返回一个html。这种需要响应快,调用频繁就适合线程,而且开一个线程开销很小。