Julia中的共享数组对println产生奇怪的反应

时间:2019-03-18 16:09:28

标签: arrays loops parallel-processing julia

我的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

1 个答案:

答案 0 :(得分:2)

@distributed宏不会等待工作者在这样的for循环中完成计算。它只是开始计算。因此,这意味着如果i循环执行尚未完成,则j循环可能会乱序发生-并且看来打印时间足以防止这种情况发生。

要解决此问题,只需在分布式宏之前放置一个@sync