Parallel processing 并行计算与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) )

我在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) )
   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

我注意到串行版本在代码的计时部分略快于并行版本。而且,总执行时间有很大的差异

问题

  • 为什么并行化版本速度较慢?(我做错了什么?)
  • 哪个是并行化这个程序的正确方法
注:我将pmap与vcat结合使用,因为我也想尝试使用中间值

谢谢你的帮助


编辑

我按照@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中,给出与原始代码相同的结果。