平行
@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