平行

@parallel 可用於並行化迴圈,將迴圈的步驟分配給不同的工作者。作為一個非常簡單的例子:

addprocs(3)

a = collect(1:10)

for idx = 1:10
    println(a[idx])
end

有關更復雜的示例,請考慮:

@time begin
    @sync begin
        @parallel for idx in 1:length(a)
            sleep(a[idx])
        end
    end
end
27.023411 seconds (13.48 k allocations: 762.532 KB)
julia> sum(a)
55

因此,我們看到如果我們在沒有 @parallel 的情況下執行了這個迴圈,那麼執行它將花費 55 秒而不是 27 秒。

我們還可以為 @parallel 巨集提供減少運算子。假設我們有一個陣列,我們想要對陣列的每一列求和,然後將這些和相乘:

A = rand(100,100);

@parallel (*) for idx = 1:size(A,1)
    sum(A[:,idx])
end

使用 @parallel 避免意外行為時,需要記住幾件重要的事情。

第一: 如果你想在你的迴圈中使用不在基礎 Julia 中的任何函式(例如你在指令碼中定義的函式或從包中匯入的函式),那麼你必須使這些函式可以被 worker 使用。因此,例如,以下將工作:

myprint(x) = println(x)
for idx = 1:10
    myprint(a[idx])
end

相反,我們需要使用:

@everywhere begin
    function myprint(x) 
        println(x)
    end
end

@parallel for idx in 1:length(a)
    myprint(a[idx])
end

第二,雖然每個工作人員都能夠訪問控制器範圍內的物件,但他們無法修改它們。從而

a = collect(1:10)
@parallel for idx = 1:length(a)
   a[idx] += 1
end

julia> a'
1x10 Array{Int64,2}:
 1  2  3  4  5  6  7  8  9  10

然而,如果我們已經執行了 @parallel 的迴圈,它將成功修改陣列 a

為了解決這個問題,我們可以將 a 設為 SharedArray 型別的物件,以便每個工作人員都可以訪問和修改它:

a = convert(SharedArray{Float64,1}, collect(1:10))
@parallel for idx = 1:length(a)
    a[idx] += 1
end

julia> a'
1x10 Array{Float64,2}:
 2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0  10.0  11.0