使用Julia @parallel和SharedArray进行并行计算

时间:2018-02-14 03:42:57

标签: parallel-processing julia

我一直在尝试使用@parallelSharedArray在Julia中实现一些并行编程。

Xi = Array{Float64}([0.0, 450.0, 450.0, 0.0, 0.0, 450.0, 450.0, 0.0])
Yi = Array{Float64}([0.0, 0.0, 600.0, 600.0, 0.0, 0.0, 600.0, 600.0])
Zi = Array{Float64}([0.0, 0.0, 0.0, 0.0, 400.0, 400.0, 400.0, 400.0])
Xj = Array{Float64}([0.0, 450.0, 450.0, 0.0, 0.0, 450.0, 450.0, 0.0])
Yj = Array{Float64}([0.0, 0.0, 600.0, 600.0, 0.0, 0.0, 600.0, 600.0])
Zj = Array{Float64}([0.0, 0.0, 0.0, 0.0, 400.0, 400.0, 400.0, 400.0])
L = Array{Float64}([400.0, 400.0, 400.0, 400.0, 450.0, 600.0, 450.0, 600.0])
Rot = Array{Float64}([90.0, 90.0, 90.0, 90.0, 0.0, 0.0, 0.0, 0.0])

显然这些载体会很大,但为了简单起见,我只是把这个有限的尺寸。

这是没有并行计算的操作:

function jt_transcoord(Xi, Yi, Zi, Xj, Yj, Zj, Rot, L)
r = Vector(length(Xi))
for i in 1:length(Xi)
    rxX = (Xj[i] - Xi[i]) / L[i]
    rxY = (Yj[i] - Yi[i]) / L[i]
    rxZ = (Zj[i] - Zi[i]) / L[i]
        if rxX == 0 && rxY == 0
            r[i] = [0 0 rxZ; cosd(Rot[i]) -rxZ*sind(Rot[i]) 0; sind(Rot[i]) rxZ*cosd(Rot[i]) 0]
        else
            R=sqrt(rxX^2+rxY^2)
            r21=(-rxX*rxZ*cosd(Rot[i])+rxY*sind(Rot[i]))/R
            r22=(-rxY*rxZ*cosd(Rot[i])-rxX*sind(Rot[i]))/R
            r23=R*cosd(Rot[i])
            r31=(rxX*rxZ*sind(Rot[i])+rxY*cosd(Rot[i]))/R
            r32=(rxY*rxZ*sind(Rot[i])-rxX*cosd(Rot[i]))/R
            r33=-R*sind(Rot[i])
            r[i] = [rxX rxY rxZ;r21 r22 r23;r31 r32 r33]
        end
end
return r
end

返回的值基本上是一个包含每个向量行中的矩阵的数组。看起来像这样:

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], 
[1.0 0.0 0.0; 0.0 -0.0 1.0; 0.0 -1.0 -0.0], 
[0.0 1.0 0.0; 0.0 -0.0 1.0; 1.0 0.0 -0.0], 
[-1.0 0.0 0.0; 0.0 0.0 1.0; 0.0 1.0 -0.0], 
[0.0 -1.0 0.0; -0.0 0.0 1.0; -1.0 -0.0 -0.0]]

这是我使用@parallel的功能。首先,我需要将向量转换为SharedArray s:

Xi = convert(SharedArray, Xi)
Yi = convert(SharedArray, Yi)
Zi = convert(SharedArray, Zi)
Xj = convert(SharedArray, Xj)
Yj = convert(SharedArray, Yj)
Zj = convert(SharedArray, Zj)
L = convert(SharedArray, L)
Rot = convert(SharedArray, Rot)

这是相同的代码,但使用@parallel

function jt_transcoord_parallel(Xi, Yi, Zi, Xj, Yj, Zj, Rot, L)
r = SharedArray{Float64}(zeros((length(Xi),1)))
@parallel for i in 1:length(Xi)
    rxX = (Xj[i] - Xi[i]) / L[i]
    rxY = (Yj[i] - Yi[i]) / L[i]
    rxZ = (Zj[i] - Zi[i]) / L[i]
        if rxX == 0 && rxY == 0
            r[i] = [0 0 rxZ; cosd(Rot[i]) -rxZ*sind(Rot[i]) 0; sind(Rot[i]) rxZ*cosd(Rot[i]) 0]
        else
            R=sqrt(rxX^2+rxY^2)
            r21=(-rxX*rxZ*cosd(Rot[i])+rxY*sind(Rot[i]))/R
            r22=(-rxY*rxZ*cosd(Rot[i])-rxX*sind(Rot[i]))/R
            r23=R*cosd(Rot[i])
            r31=(rxX*rxZ*sind(Rot[i])+rxY*cosd(Rot[i]))/R
            r32=(rxY*rxZ*sind(Rot[i])-rxX*cosd(Rot[i]))/R
            r33=-R*sind(Rot[i])
            r[i] = [rxX rxY rxZ;r21 r22 r23;r31 r32 r33]
        end
end
return r
end

我刚刚得到了一个零矢量。我的问题是:有没有办法在Julia中使用@parallel实现此功能,并获得与原始函数中相同的结果?

1 个答案:

答案 0 :(得分:2)

函数jt_transcoordjt_transcoord_parallel存在重大编码缺陷。

jt_transcoord中,您将数组分配给向量元素位置。例如,您编写r = Vector(length(Xi))然后分配r[i] = [rxX rxY rxZ;r21 r22 r23;r31 r32 r33]。但是r[i]应该是数字,而是为其分配3x3 矩阵。我怀疑朱莉娅正在为你悄悄改变类型。

SharedArray个对象不会接受此松散类型转换行为。 SharedArray的组件必须是Float64,例如Vector{Matrix}r = SharedArray{Float64}(length(Xi)) for i in 1:length(Xi) rxX = (Xj[i] - Xi[i]) / L[i] rxY = (Yj[i] - Yi[i]) / L[i] rxZ = (Zj[i] - Zi[i]) / L[i] if rxX == 0 && rxY == 0 r[i] = [0 0 rxZ; cosd(Rot[i]) -rxZ*sind(Rot[i]) 0; sind(Rot[i]) rxZ*cosd(Rot[i]) 0] else R = sqrt(rxX^2+rxY^2) r21 = (-rxX*rxZ*cosd(Rot[i])+rxY*sind(Rot[i]))/R r22 = (-rxY*rxZ*cosd(Rot[i])-rxX*sind(Rot[i]))/R r23 = R*cosd(Rot[i]) r31 = (rxX*rxZ*sind(Rot[i])+rxY*cosd(Rot[i]))/R r32 = (rxY*rxZ*sind(Rot[i])-rxX*cosd(Rot[i]))/R r33 = -R*sind(Rot[i]) r[i] = [rxX rxY rxZ;r21 r22 r23;r31 r32 r33] end end 不是基本类型。打开Julia v0.6 REPL并复制/粘贴以下代码:

ERROR: MethodError: Cannot `convert` an object of type Array{Float64,2} to an object of type Float64
This may have arisen from a call to the constructor Float64(...),
since type constructors fall back to convert methods.
Stacktrace:
 [1] setindex!(::SharedArray{Float64,2}, ::Array{Float64,2}, ::Int64) at ./sharedarray.jl:483
 [2] macro expansion at ./REPL[26]:6 [inlined]
 [3] anonymous at ./<missing>:?

在我结束时,我得到:

SharedArray

基本上,Julia告诉你它无法为Vector{Matrix}向量分配矩阵。

你有什么选择?

  • 如果您坚持使用r = Vector{Matrix{Float64}}(length(Xi))返回类型,请在jt_transcoord中使用SharedArray。但由于Vector{Matrix}不是可接受的原始类型,因此您无法使用SharedArray
  • 或者,如果您愿意使用张量(即3路阵列)操作,那么您可以使用下面的伪码A.但function jt_transcoord_tensor(Xi, Yi, Zi, Xj, Yj, Zj, Rot, L) # initialize array r = Array{Float64}(3,3,length(Xi)) # r = SharedArray{Float64,3}((3,3,length(Xi))) # for SharedArrays for i in 1:length(Xi) # @parallel for i in 1:length(Xi) # for SharedArrays # other code... r[:,:,i] = [0 0 rxZ; cosd(Rot[i]) -rxZ*sind(Rot[i]) 0; sind(Rot[i]) rxZ*cosd(Rot[i]) 0] # other code... r[:,:,i] = [rxX rxY rxZ;r21 r22 r23;r31 r32 r33] end end return r end 计算只会帮助您仔细考虑哪个进程拥有张量的哪个部分。否则,进程将需要相互通信,并且并行化的函数可能执行得非常慢。
  • 如果您愿意以3n x 3列方式放置3x3矩阵,那么您可以使用下面的伪代码B.

伪代码A

function jt_transcoord_parallel(Xi, Yi, Zi, Xj, Yj, Zj, Rot, L)
    n = length(Xi)
    r = SharedArray{Float64}((3*n,3))
    @parallel for i in 1:length(Xi)
            # other code...
            r[(3*(i-1)+1):3*(i),:] = [0 0 rxZ; cosd(Rot[i]) -rxZ*sind(Rot[i]) 0; sind(Rot[i]) rxZ*cosd(Rot[i]) 0]
            # other code...
            r[(3*(i-1)+1):3*(i),:] = [rxX rxY rxZ;r21 r22 r23;r31 r32 r33]
        end
    end
    return r
end

伪代码B

{{1}}