以下是正确的操作方法(在撰写本答案时,其他答案不起作用-请参见我的评论)。
我将使用比问题中略微简单的例子(但非常相似)。
1. 非并行版本(基准方案)
using Random
const m = MersenneTwister(0);
function dothestuff!(out_N, N, ic, m)
out_N[:, ic] .= rand(m, N)
end
function dummy_base(m=m, N=100_000,c=256)
out_N = Array{Float64}(undef,N,c)
for ic in 1:c
dothestuff!(out_N, N, ic, m)
end
out_N
end
测试:
julia> using BenchmarkTools; @btime dummy_base();
106.512 ms (514 allocations: 390.64 MiB)
2. 使用线程并行化
using Random
const mt = MersenneTwister.(1:Threads.nthreads());
function dothestuff!(out_N, N, ic, m)
out_N[:, ic] .= rand(m, N)
end
function dummy_threads(mt=mt, N=100_000,c=256)
out_N = Array{Float64}(undef,N,c)
Threads.@threads for ic in 1:c
dothestuff!(out_N, N, ic, mt[Threads.threadid()])
end
out_N
end
让我们来测试性能:
julia> using BenchmarkTools; @btime dummy_threads();
46.775 ms (535 allocations: 390.65 MiB)
3. 使用进程实现并行化(在单台机器上)
using Distributed
addprocs(4)
using Random, SharedArrays
@everywhere using Random, SharedArrays, Distributed
@everywhere Random.seed!(myid())
@everywhere function dothestuff!(out_N, N, ic)
out_N[:, ic] .= rand(N)
end
function dummy_distr(N=100_000,c=256)
out_N = SharedArray{Float64}(N,c)
@sync @distributed for ic in 1:c
dothestuff!(out_N, N, ic)
end
out_N
end
性能(注意,进程间通信需要一些时间,因此对于小型计算,线程通常更好):
julia> using BenchmarkTools; @btime dummy_distr();
62.584 ms (1073 allocations: 45.48 KiB)
N[:, i]
将更快。而且,如果避免使用向量化代码,性能可能会更好。最后,如果手动指定线程本地的随机数生成器,则多线程的rand
通常最快。 - mbauman