朱莉娅:如何并行执行功能?

时间:2018-06-21 14:57:03

标签: parallel-processing julia

我想并行运行功能。这些功能会循环执行多次。

coordSys = SharedArray{Bool}([true,false,true,true]);
dir = SharedArray{Int8}([1,2,3,2]);
load = SharedArray{Float64}([8,-7.5,7,-8.5]);
L = SharedArray{Float64}([400,450,600,500]);
r = SharedArray{Float64}([0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
                          0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
                          0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
                          0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0]);

显然,这些向量将是巨大的,但为简单起见,我只设置了有限的大小。

无需并行计算的操作:

function unifLoad(coordSys,dir,load,L,ri)
    if coordSys == true
        if dir == 1
            Q = [load;0;0];
        elseif dir == 2
            Q = [0;load;0];
        elseif dir == 3
            Q = [0;0;load];
        end
        q = ri*Q; #matrix multiplication
        P = q[1]*L/2;
        V = q[2]*L/2;
        M = -q[3]*L*L/12;
        f = [P;V;M];
    else
        f = [1.0;1.0;1.0];
    end
    return f
end

运行循环:

var = zeros(12)
for i = 1:length(L)
    var[3*(i-1)+1:3*i] = unifLoad(coordSys[i],dir[i],load[i],L[i],r[3*(i-1)+1:3*i,:]);
end

返回值是:

var
12-element Array{Float64,1}:
    0.0      
    0.0      
   -1.06667e5
    1.0      
    1.0      
    1.0      
 2100.0      
    0.0      
   -0.0      
    0.0      
 2125.0      
   -0.0

并行计算操作

我一直在尝试并行实现相同的功能,但没有得到相同的结果。

# addprocs(3)

@everywhere function unifLoad_Parallel(coordSys,dir,load,L,ri)
    if coordSys == true
        if dir == 1
            Q = [load;0;0];
        elseif dir == 2
            Q = [0;load;0];
        elseif dir == 3
            Q = [0;0;load];
        end
        q = ri*Q; # Matrix multiplication (ri -> Array 3x3)
        P = q[1]*L/2;
        V = q[2]*L/2;
        M = -q[3]*L*L/12;
        f = [P;V;M];
    else
        f = [1.0;1.0;1.0];
    end
    return f
end 

运行并行循环:

var_parallel = SharedArray{Float64}(12);

@parallel for i = 1:length(L)
        var_parallel[3*(i-1)+1:3*i] = unifLoad_Parallel(coordSys[i],dir[i],load[i],L[i],r[3*(i-1)+1:3*i,:]);
end

返回值是:

var_parallel
12-element SharedArray{Float64,1}:
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0
 0.0

1 个答案:

答案 0 :(得分:0)

在我的Julia 0.6.3上,并行代码返回的结果相同,因此我无法重现该问题(而且我也没有遇到问题@SalchiPapa报告)。

但是,我想指出的是,这段代码实际上应该在线程上更快地工作(我认为真正的问题要大得多)。这是您可以使用的代码(我使用了与您稍短的等效实现-但是唯一有意义的变化是我将其包装在可以显着提高性能的函数中)。关键问题是共享var以外的所有数组,但只能读取。 var被写入,但每个条目仅被写入一次,并且不被读取。在这种情况下,使用开销较低的线程是安全的。

这是示例代码(您必须在启动Julia之前定义JULIA_NUM_TREADS环境变量并将其设置为所需的线程数-很可能是4是您想要的):

using Base.Threads

function experiment()
    coordSys = [true,false,true,true];
    dir = [1,2,3,2];
    load = [8,-7.5,7,-8.5];
    L = [400,450,600,500];
    r = [0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
         0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
         0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
         0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0];

    unifLoad(coordSys,dir,load,L,r, i) =
        coordSys ? load * L * r[3*(i-1)+1:3*i, dir] .* [0.5, 0.5, -L/12] : [1.0, 1.0, 1.0]

    var = zeros(12)
    @threads for i = 1:length(L)
        var[3*(i-1)+1:3*i] = unifLoad(coordSys[i],dir[i],load[i],L[i],r,i);
    end
    var
end

这也是使用类似思路进行并行处理的简化代码:

coordSys = SharedArray{Bool}([true,false,true,true]);
dir = SharedArray{Int8}([1,2,3,2]);
load = SharedArray{Float64}([8,-7.5,7,-8.5]);
L = SharedArray{Float64}([400,450,600,500]);
r = SharedArray{Float64}([0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
                          0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
                          0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0 
                          0.0 0.0 1.0; 0.0 -1.0 0.0; 1.0 0.0 0.0]);

@everywhere unifLoad(coordSys,dir,load,L,r,i) =
        coordSys ? load * L * r[3*(i-1)+1:3*i, dir] .* [0.5, 0.5, -L/12] : [1.0, 1.0, 1.0]

vcat(pmap(i -> unifLoad(coordSys[i],dir[i],load[i],L[i],r,i), 1:length(L))...)

这里pmap主要用于简化代码,因此您不需要@sync