Julia Distributed 在添加进程时减慢了单核性能的一半
Julia Distributed slow down to half the single core performance when adding process
我有一个函数 func
,当 运行 在单核上运行时,它可能需要 ~50 秒。现在我想运行在一台192核CPU多次的服务器上。但是当我添加工作进程时,180 个,每个核心的性能都会下降。最差的 CPU 需要 ~100s 来计算 func
.
有人可以帮帮我吗?
这是伪代码
using Distributed
addprocs(180)
@everywhere include("func.jl") # defines func in every process
First try using only 10 workers
@sync @distributed for i in 1:10
func()
end
@sync @distributed for i in 1:10
@time func()
end
From worker #: 43.537886 seconds (243.58 M allocations: 30.004 GiB, 8.16% gc time)
From worker #: 44.242588 seconds (247.59 M allocations: 30.531 GiB, 7.90% gc time)
From worker #: 44.571170 seconds (246.26 M allocations: 30.338 GiB, 8.81% gc time)
...
From worker #: 45.259822 seconds (252.19 M allocations: 31.108 GiB, 8.25% gc time)
From worker #: 46.746692 seconds (246.36 M allocations: 30.346 GiB, 11.21% gc time)
From worker #: 47.451914 seconds (248.94 M allocations: 30.692 GiB, 8.96% gc time)
Seems not bad when using 10 workers
Now we use 180 workers
@sync @distributed for i in 1:180
func()
end
@sync @distributed for i in 1:180
@time func()
end
From worker #: 55.752026 seconds (245.20 M allocations: 30.207 GiB, 9.33% gc time)
From worker #: 57.031739 seconds (245.00 M allocations: 30.176 GiB, 7.70% gc time)
From worker #: 57.552505 seconds (247.76 M allocations: 30.543 GiB, 7.34% gc time)
...
From worker #: 96.850839 seconds (247.33 M allocations: 30.470 GiB, 7.95% gc time)
From worker #: 97.468060 seconds (250.04 M allocations: 30.827 GiB, 6.96% gc time)
From worker #: 98.078816 seconds (250.55 M allocations: 30.883 GiB, 10.87% gc time)
时间从 55 秒到 100 秒几乎呈线性增长。
我已通过 top
命令检查 CPU 使用率可能不是瓶颈(“id”保持 >2%)。 RAM 使用率也一样(使用了 ~20%)。
其他版本信息:
朱莉娅版本 1.5.3
平台信息:
OS: Linux (x86_64-pc-linux-gnu)
CPU:Intel(R) Xeon(R) Platinum 9242 CPU @ 2.30GHz
更新:
- 将
func
替换为最小示例(简单的 for 循环)不会改变减速。
- 将进程数减少到 192/2 可以缓解减速
新的伪代码是
addprocs(96)
@everywhere function ss()
sum=0
for i in 1:1000000000
sum+=sin(i)
end
end
@sync @distributed for i in 1:10
ss()
end
@sync @distributed for i in 1:10
@time ss()
end
From worker #: 32.8 seconds ..(8 others).. 34.0 seconds
...
@sync @distributed for i in 1:96
@time ss()
end
From worker #: 38.1 seconds ..(94 others).. 45.4 seconds
您正在测量每个工作人员执行 func()
所花费的时间,并观察到从 10 个进程到 180 个并行进程时单个进程的性能下降。
这对我来说很正常:
- Intel 核心使用超线程,因此您实际上拥有 96 个核心(更详细地说 - 超线程核心仅增加 20-30% 的性能)。这意味着您的 168 个进程需要共享 84 个超线程内核,而 12 个进程获得完整的 12 个内核。
- CPU 速度由油门温度决定 (https://en.wikipedia.org/wiki/Thermal_design_power) 当然还有更多 space 当 运行 10 个进程 vs 180 个进程
- 您的任务显然在争夺内存。他们总共分配了超过 5TB 的内存,而你的机器分配的内存比这少得多。垃圾收集的最后一英里始终是最昂贵的一英里 - 因此,如果您的垃圾收集器被挤压并争夺内存,则性能会参差不齐,垃圾收集时间会出奇地长。
查看此数据我建议您尝试:
addprocs(192 ÷ 2)
然后看看性能将如何变化。
我有一个函数 func
,当 运行 在单核上运行时,它可能需要 ~50 秒。现在我想运行在一台192核CPU多次的服务器上。但是当我添加工作进程时,180 个,每个核心的性能都会下降。最差的 CPU 需要 ~100s 来计算 func
.
有人可以帮帮我吗?
这是伪代码
using Distributed
addprocs(180)
@everywhere include("func.jl") # defines func in every process
First try using only 10 workers
@sync @distributed for i in 1:10
func()
end
@sync @distributed for i in 1:10
@time func()
end
From worker #: 43.537886 seconds (243.58 M allocations: 30.004 GiB, 8.16% gc time)
From worker #: 44.242588 seconds (247.59 M allocations: 30.531 GiB, 7.90% gc time)
From worker #: 44.571170 seconds (246.26 M allocations: 30.338 GiB, 8.81% gc time)
...
From worker #: 45.259822 seconds (252.19 M allocations: 31.108 GiB, 8.25% gc time)
From worker #: 46.746692 seconds (246.36 M allocations: 30.346 GiB, 11.21% gc time)
From worker #: 47.451914 seconds (248.94 M allocations: 30.692 GiB, 8.96% gc time)
Seems not bad when using 10 workers
Now we use 180 workers
@sync @distributed for i in 1:180
func()
end
@sync @distributed for i in 1:180
@time func()
end
From worker #: 55.752026 seconds (245.20 M allocations: 30.207 GiB, 9.33% gc time)
From worker #: 57.031739 seconds (245.00 M allocations: 30.176 GiB, 7.70% gc time)
From worker #: 57.552505 seconds (247.76 M allocations: 30.543 GiB, 7.34% gc time)
...
From worker #: 96.850839 seconds (247.33 M allocations: 30.470 GiB, 7.95% gc time)
From worker #: 97.468060 seconds (250.04 M allocations: 30.827 GiB, 6.96% gc time)
From worker #: 98.078816 seconds (250.55 M allocations: 30.883 GiB, 10.87% gc time)
时间从 55 秒到 100 秒几乎呈线性增长。
我已通过 top
命令检查 CPU 使用率可能不是瓶颈(“id”保持 >2%)。 RAM 使用率也一样(使用了 ~20%)。
其他版本信息: 朱莉娅版本 1.5.3 平台信息: OS: Linux (x86_64-pc-linux-gnu) CPU:Intel(R) Xeon(R) Platinum 9242 CPU @ 2.30GHz
更新:
- 将
func
替换为最小示例(简单的 for 循环)不会改变减速。 - 将进程数减少到 192/2 可以缓解减速
新的伪代码是
addprocs(96)
@everywhere function ss()
sum=0
for i in 1:1000000000
sum+=sin(i)
end
end
@sync @distributed for i in 1:10
ss()
end
@sync @distributed for i in 1:10
@time ss()
end
From worker #: 32.8 seconds ..(8 others).. 34.0 seconds
...
@sync @distributed for i in 1:96
@time ss()
end
From worker #: 38.1 seconds ..(94 others).. 45.4 seconds
您正在测量每个工作人员执行 func()
所花费的时间,并观察到从 10 个进程到 180 个并行进程时单个进程的性能下降。
这对我来说很正常:
- Intel 核心使用超线程,因此您实际上拥有 96 个核心(更详细地说 - 超线程核心仅增加 20-30% 的性能)。这意味着您的 168 个进程需要共享 84 个超线程内核,而 12 个进程获得完整的 12 个内核。
- CPU 速度由油门温度决定 (https://en.wikipedia.org/wiki/Thermal_design_power) 当然还有更多 space 当 运行 10 个进程 vs 180 个进程
- 您的任务显然在争夺内存。他们总共分配了超过 5TB 的内存,而你的机器分配的内存比这少得多。垃圾收集的最后一英里始终是最昂贵的一英里 - 因此,如果您的垃圾收集器被挤压并争夺内存,则性能会参差不齐,垃圾收集时间会出奇地长。
查看此数据我建议您尝试:
addprocs(192 ÷ 2)
然后看看性能将如何变化。