gpt4 book ai didi

ruby - 在 Ruby 中运行多线程 Open3 调用

转载 作者:太空宇宙 更新时间:2023-11-03 18:03:54 24 4
gpt4 key购买 nike

我有一个大循环,我试图在线程中运行对 Open3.capture3 的调用,而不是线性运行。每个线程应该独立运行,并且在访问数据方面没有死锁。

问题是,线程版本太慢了,它占用了我的 CPU。

这是线性规划的一个例子:

require 'open3'

def read(i)
text, _, _ = Open3.capture3("echo Hello #{i}")
text.strip
end

(1..400).each do |i|
puts read(i)
end

这是线程版本:

require 'open3'
require 'thread'

def read(i)
text, _, _ = Open3.capture3("echo Hello #{i}")
text.strip
end

threads = []
(1..400).each do |i|
threads << Thread.new do
puts read(i)
end
end

threads.each(&:join)

时间比较:

$ time ruby linear.rb
ruby linear.rb 0.36s user 0.12s system 110% cpu 0.433 total
------------------------------------------------------------
$ time ruby threaded.rb
ruby threaded.rb 1.05s user 0.64s system 129% cpu 1.307 total

最佳答案

Each thread should run independently and there's no deadlock in terms of accessing data.

你确定吗?

threads << Thread.new do
puts read(i)
end

您的线程正在共享标准输出。如果你查看你的输出,你会发现你没有得到任何交错的文本输出,因为 Ruby 自动确保 stdout 上的互斥,所以你的线程有效地串行运行,有一堆无用的构造/解构/切换浪费时间。

Ruby 中的线程仅在调用某些 Rubyless 上下文时才对并行有效*。这样虚拟机就知道它可以安全地并行运行而线程不会相互干扰。看看如果我们只捕获线程中的 shell 输出会发生什么:

threads = Array.new(400) { |i| Thread.new { `echo Hello #{i}` } }
threads.each(&:join)
# time: 0m0.098s

与连续

output = Array.new(400) { |i| `echo Hello #{i}` }
# time: 0m0.794s

* 事实上,这取决于几个因素。一些 VM (JRuby) 使用 native 线程,并且更容易并行化。某些 Ruby 表达式比其他表达式更可并行化(取决于它们与 GVL 的交互方式)。确保并行性的最简单方法是运行单个外部命令,例如子进程或系统调用,这些通常是无 GVL 的。

关于ruby - 在 Ruby 中运行多线程 Open3 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54132337/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com