我的Julia版本是Windows 10上运行的1.0.1。
我对2d数组进行了一些操作,尝试并行化。为此,我首先将数组的索引拆分为非重叠集,以便处理给定的索引集无需并发访问数组的同一单元格,因此可以在同时没有数据丢失。我的数组是2d 共享数组,我使用 @distributed 宏在循环中实现并行性。即
我有以下功能
using Distributed
using SharedArrays
function compute(Z, reg)
# Z is a 2d Shared array, reg is an array of indices described above.
N = size(Z,1);
q = true;
while (q == true)
q = false;
for i = 1:length(reg)
@distributed for j = 1:length(reg[i])
# reg[i] is defined so that the cells of Z used in this loop do NOT intersect
k = reg[i][j];
if (Z[ k ] >= 4 )
q = true;
Z[k] -= 4;
Z[k + 1] += 1;
Z[k - 1] += 1;
Z[k + N] += 1;
Z[k - N] += 1;
end
end
#println(typeof(Z));
end
end
return Z;
end
此函数以当前形式显示会产生错误结果(请参见下面的数据),但是,当我删除 println(typoef(Z))上的注释时,结果变为正确。如果我使用标准循环而不是 @distributed 循环,结果也是正确,因此,代码的逻辑缺陷并不是我的逻辑,而是我使用共享数组和@distributed循环。
我的问题: println 为什么会影响共享阵列的性能?
我了解这不是 println 本身,但也许以某种方式println会强制所有分布式循环在数组的同一副本上操作,而没有它,每个循环中的数组都是单独的副本原始数组。
我希望对这个问题有任何见解,并提出在这种情况下正确使用共享数组和分布式循环的建议。
后面的内容可以跳过,上面的功能所基于的数据以及过程的结果。
这是我的数组 Z 中的示例数据,然后馈入函数 compute
0 0 0 0 0 0 0
0 0 2 6 2 0 0
0 2 4 2 4 2 0
0 6 2 0 2 6 0
0 2 4 2 4 2 0
0 0 2 6 2 0 0
0 0 0 0 0 0 0
数组类型为:
SharedArrays.SharedArray{UInt8,2}
这些是我使用的索引区域(我的数组是7x7,但是我在这里使用线性索引)
9-element Array{Any,1}:
Int32[1, 4, 7, 22, 25, 28, 43, 46, 49]
Int32[8, 11, 14, 29, 32, 35]
Int32[15, 18, 21, 36, 39, 42]
Int32[2, 5, 23, 26, 44, 47]
Int32[9, 12, 30, 33]
Int32[16, 19, 37, 40]
Int32[3, 6, 24, 27, 45, 48]
Int32[10, 13, 31, 34]
Int32[17, 20, 38, 41]
关闭#println的 compute(Z,reg)的结果(错误的结果):
0 0 0 1 0 0 0
0 0 4 2 4 1 0
0 4 0 5 1 0 1
1 2 5 0 5 4 1
0 4 1 5 2 0 1
0 1 0 4 0 2 0
0 0 1 1 1 0 0
打开 println 的结果(正确的结果)
0 0 1 2 1 0 0
0 2 2 2 2 2 0
1 2 2 2 2 2 1
2 2 2 0 2 2 2
1 2 2 2 2 2 1
0 2 2 2 2 2 0
0 0 1 2 1 0 0
答案 0 :(得分:2)
@distributed
宏不会等待工作者在这样的for
循环中完成计算。它只是开始计算。因此,这意味着如果i
循环执行尚未完成,则j
循环可能会乱序发生-并且看来打印时间足以防止这种情况发生。
要解决此问题,只需在分布式宏之前放置一个@sync
。