我有一台主要运行 Ruby 脚本的服务器。由于 Ruby (2.7) 具有 GIL,因此它是单线程的。
我的计算机(服务器)有 Intel i3 双核处理器,但由于超线程,我看到 4 个核心。Ruby 在高负载下仅利用 25% 的 CPU。我想看看禁用超线程是否对在单线程上运行的编程语言有益。
此外,我的服务器运行的是极简桌面环境,并且 CPU 使用率不超过 2%。因此,我想让 Ruby 充分利用大部分资源。我进行了基准测试,看看禁用超线程是否真的能提高性能。
基准:
我编写了一个简单的 Ruby 脚本,运行一个 while 循环,并将循环计数器的值与另一个变量相加。此程序应使用 100% 的 CPU 核心:
#!/usr/bin/env ruby
$-v = true
LOOPS = ENV['N'].to_i.then { |x| x < 1 ? 100_000_000 : x } + 1
i, j, t = 0, 0, Time.now
puts "Counting till #{LOOPS - 1} and adding values to V..."
while (i += 1) < LOOPS
if i % 10000 == 0
e = Time.now - t
r = LOOPS.*(e)./(i).-(e).round(2)
print "\e[2KN: #{i} | Done: #{i.*(100) / LOOPS}% | Elapsed: #{e.round(2)}s | Estimated Rem: #{r}s\r"
end
j += i
end
puts "\nV = #{j}\nTime: #{(Time.now).-(t).round(2)}s"
- 使用超线程:
⮚ ruby p.rb
Counting till 100000000 and adding values to V...
N: 100000000 | Done: 99% | Elapsed: 4.55s | Estimated Rem: 0.0s
V = 5000000050000000
Time: 4.55s
⮚ ruby p.rb
Counting till 100000000 and adding values to V...
N: 100000000 | Done: 99% | Elapsed: 4.54s | Estimated Rem: 0.0s
V = 5000000050000000
Time: 4.54s
⮚ ruby p.rb
Counting till 100000000 and adding values to V...
N: 100000000 | Done: 99% | Elapsed: 4.67s | Estimated Rem: 0.0s
V = 5000000050000000
Time: 4.67s
gnome 系统监视器报告称测试运行时 Ruby 的 CPU 占用率为 25%。
- 没有超线程:
[# echo 0 | tee /sys/devices/system/cpu/cpu{2,3}/online
用于禁用超线程]
⮚ ruby p.rb
Counting till 100000000 and adding values to V...
N: 100000000 | Done: 99% | Elapsed: 4.72s | Estimated Rem: 0.0s
V = 5000000050000000
Time: 4.72s
⮚ ruby p.rb
Counting till 100000000 and adding values to V...
N: 100000000 | Done: 99% | Elapsed: 4.54s | Estimated Rem: 0.0s
V = 5000000050000000
Time: 4.54s
⮚ ruby p.rb
Counting till 100000000 and adding values to V...
N: 100000000 | Done: 99% | Elapsed: 4.56s | Estimated Rem: 0.0s
V = 5000000050000000
Time: 4.56s
gnome 系统监视器报告称测试运行时 Ruby 的 CPU 使用率为 50%。
我甚至在笔记本电脑上运行了测试,这花费的时间大约是计算机上的两倍。但结果是一样的:禁用超线程并不能帮助进程做得更好。更糟糕的是,我的笔记本电脑在多任务处理时会变慢一点。
因此,在非超线程模式下,Ruby 使用的 CPU 功率是超线程模式下的 2 倍。但为什么完成相同任务仍需要相同的时间?
答案1
你的 Ruby 程序确实不是在禁用超线程的情况下运行时,使用 2 倍的 CPU 时间。相反,由于它最大化了两个核心中的一个核心,因此gnome-system-monitor
将报告利用率为 50%。如果由于超线程,系统报告总共有四个核心,那么四个核心中的一个核心的利用率为 25%。
禁用 HT 确实会导致结果出现更多差异,因为可用的资源更少:最近的 Intel(或 AMD)核心非常宽,因此额外的线程通常有助于提高 10-20% 的总性能。如果在测试运行期间自动执行了某些后台进程,则没有 HT 的系统容易出现更多差异和较低的总吞吐量。
答案2
我想看看禁用超线程是否有利于在单线程上运行的编程语言。
我不知道减少核心数量如何能提高性能,即使对于单线程应用程序也是如此。启用超线程后,您的 CPU 将使用 4 个虚拟核心运行。使用所有 CPU 的单线程应用程序将使用 25% 的可用 CPU。禁用超线程后,核心数量将减少到 2 个。现在,该单线程应用程序可以使用 50% 的可用 CPU。
Ruby 不会使用 2 倍的 CPU,而是当您禁用超线程时,您只有 1/2 的 CPU 可用。如果您有一个大杯子,里面有 1/4 满的水,然后将其倒入一个较小的杯子中,杯子里会变成 1/2 满的水,但水量仍然相同。
我甚至在笔记本电脑上运行了测试,这花费的时间大约是计算机上的两倍。但结果是一样的:禁用超线程并不能帮助进程做得更好。更糟糕的是,我的笔记本电脑在多任务处理时会变慢一点。
是的,你正在消耗大约一半的 CPU 能力。这也会使 Ruby 线程运行得更慢。假设除了 Ruby 线程之外,还有 3 个线程需要同时运行。如果你将虚拟核心减少到 2 个,那么你的 Ruby 线程很可能会暂停至少一段时间,以便让另一个线程有时间运行。