Parallel processing 并行计算与Julia
我在Julia中遇到了一些并行计算的性能问题。朱莉娅和平行计算我都是新手 为了学习,我并行化了一段应该从并行化中获益的代码,但它没有 该程序估计其元素以均匀分布随机选择的阵列组件的平均值 系列版本Parallel processing 并行计算与Julia,parallel-processing,julia,Parallel Processing,Julia,我在Julia中遇到了一些并行计算的性能问题。朱莉娅和平行计算我都是新手 为了学习,我并行化了一段应该从并行化中获益的代码,但它没有 该程序估计其元素以均匀分布随机选择的阵列组件的平均值 系列版本 tic() function mean_estimate(N::Int) iter = 100000*2 p = 5000 vec_mean = zeros(iter) for i = 1:iter vec_mean[i] = mean( rand(p) )
tic()
function mean_estimate(N::Int)
iter = 100000*2
p = 5000
vec_mean = zeros(iter)
for i = 1:iter
vec_mean[i] = mean( rand(p) )
end
return mean(vec_mean)
end
a = mean_estimate(0)
toc()
println("The mean is: ", a)
addprocs(CPU_CORES - 1)
println("CPU cores ", CPU_CORES)
tic()
@everywhere function mean_estimate(N::Int)
iter = 100000
p = 5000
vec_mean = zeros(iter)
for i = 1:iter
vec_mean[i] = mean( rand(p) )
end
return mean(vec_mean)
end
the_mean = mean(vcat(pmap(mean_estimate,[1,2])...))
toc()
println("The mean is: ", the_mean)
并行化版本
tic()
function mean_estimate(N::Int)
iter = 100000*2
p = 5000
vec_mean = zeros(iter)
for i = 1:iter
vec_mean[i] = mean( rand(p) )
end
return mean(vec_mean)
end
a = mean_estimate(0)
toc()
println("The mean is: ", a)
addprocs(CPU_CORES - 1)
println("CPU cores ", CPU_CORES)
tic()
@everywhere function mean_estimate(N::Int)
iter = 100000
p = 5000
vec_mean = zeros(iter)
for i = 1:iter
vec_mean[i] = mean( rand(p) )
end
return mean(vec_mean)
end
the_mean = mean(vcat(pmap(mean_estimate,[1,2])...))
toc()
println("The mean is: ", the_mean)
注:
- 串行代码第四行中的系数2是因为我在一台有两个内核的PC上尝试了该代码
- 我检查了两个内核的使用情况,看起来还可以
me@pentium-ws:~/average$ time julia serial.jl
elapsed time: 2.68671022 seconds
The mean is: 0.49999736055814215
real 0m2.961s
user 0m2.928s
sys 0m0.116s
及
我注意到串行版本在代码的计时部分略快于并行版本。而且,总执行时间有很大的差异
问题
- 为什么并行化版本速度较慢?(我做错了什么?)
- 哪个是并行化这个程序的正确方法
编辑 我按照@HighPerformanceMark的建议测量了时间。tic()/toc()时间如下所示。每种情况的迭代次数为2E6
Array Size Single thread Parallel Ratio
5000 2.69 2.89 1.07
100 000 488.77 346.00 0.71
1000 000 4776.58 4438.09 0.93
我对数组大小为什么没有明确的趋势感到困惑。您应该注意评论中的建议 正如@ChrisRackauckas指出的,类型不稳定性是执行Julia代码的常见障碍。如果您想要高性能的代码,那么请确保您的函数是正确的。考虑注释函数的返回类型<代码> pMAP和/或<代码> VCAT<代码>,例如<代码> f(pID::vector {int })=均值(VCAT(PMAP(MealPayPosits,PIDs))):FulAT64 64 /代码>或类似的东西,因为<代码> PMAP不强类型地输出它。另一个策略是运行自己的并行调度程序。您可以使用
pmap
源代码作为跳板(请参见代码)
此外,正如@AlexMorley所评论的,您通过包含编译时间混淆了您的性能度量。通常,函数f()
的性能是通过运行两次并仅测量第二次运行来衡量的。在第一次运行中,JIT编译器在运行它之前编译f()
,而第二次运行使用编译后的函数。编译会产生(不必要的)性能代价,因此,为第二次运行计时可以避免度量编译
如果可能的话。在您的代码中,您已将每个工人设置为分配其自己的零(iter)
和自己的rand(p)
。这可能会对性能产生巨大影响。代码的草图:
# code mean_estimate as two functions
f(p::Int) = mean(rand(p))
function g(iter::Int, p::Int)
vec_mean = zeros(iter)
for i in eachindex(vec_mean)
vec_mean[i] = f(p)
end
return mean(vec_mean)
end
# run twice, time on second run to get compute time
g(200000, 5000)
@time g(200000, 5000)
### output on my machine
# 2.792953 seconds (600.01 k allocations: 7.470 GB, 24.65% gc time)
# 0.4999951853035917
@time
宏提醒您,垃圾收集器在执行过程中正在清理大量分配的内存,实际上是几GB。这会影响性能。内存分配可能会掩盖串行和并行计算时间之间的任何区别
最后,请记住,并行计算会带来调度和管理单个工作人员的开销。您的工作人员正在计算长度为5000的许多随机向量的平均值。但是你可以简单地计算出500万个条目的平均值(或中位数)
x = rand(5_000_000)
mean(x)
@time mean(x) # 0.002854 seconds (5 allocations: 176 bytes)
因此,目前尚不清楚并行计算方案如何改善串行性能。当你的数组非常强大或者你的计算非常复杂时,并行计算通常会提供最好的帮助,而向量方法可能不属于这个领域
最后一点注意:您可能想看看,它使用一个公共内存池将阵列分布在多个worker上,或者是Julia中的实验设施。您可能会发现这些并行框架比
pmap
更直观,感谢回复@HighPerformanceMark,我将执行您建议的测试并对结果进行注释。pmap
的结果不是严格键入的。你应该有一个类型转换或断言。你在这里测量了很多不同的东西,包括编译和启动时间。查看有关基准测试julia代码的一些提示。@HighPerformanceMark,我编辑了答案,结果是针对更大的输入数组。谢谢@chrisrackaukas。我用@time。我在同一代码中运行了两次,尝试按照代码中的建议进行操作,输出在这里我尝试测量vcat步骤,这是代码和输出在我看来,vcat过程很快,只是因为只需要两个值。谢谢回答,我仔细阅读了它和注释。请注意我对评论的回答和随后的编辑。我不确定你发布的代码。在我的机器@time中,给出与原始代码相同的结果。