我想以非阻塞(異步)方式從 Ruby 運行多個耗時的 shell 命令。
我想將選項傳遞給命令,在 Ruby 中接收輸出,并(理想情況下)處理錯誤。
下面的腳本自然需要 15 秒的時間來執行:
測驗.rb
3.times do |i|
puts `sleep 5; echo #{i} | tail -n 1` # some time-consuming complex command
end
$ /usr/bin/time ruby test.rb
0
1
2
15.29 real 0.13 user 0.09 sys
使用Thread,它顯然可以并行執行,并且只需要 5 秒,正如預期的那樣:
threads = []
3.times do |i|
threads << Thread.new {
puts `sleep 5; echo #{i} | tail -n 1`
}
end
threads.each {|t| t.join() }
$ /usr/bin/time ruby test.rb
2
0
1
5.17 real 0.12 user 0.06 sys
但這是最好的方法嗎?還有其他方法嗎?
我也使用Open3.popen2撰寫過,但這似乎需要 15 秒才能像第一個示例一樣執行(除非包裝在執行緒中):
require 'open3'
3.times do |i|
Open3.popen2("sleep 5; echo #{i} | tail -n 1") do |stdin, stdout|
puts stdout.read()
end
end
檔案描述了“塊形式”和“非塊形式”,但是這個“塊”是指匿名函式,與并發無關,對嗎?
僅 Open3 類是否只能阻止執行?
uj5u.com熱心網友回復:
您的代碼的問題是這stdout.read是一個阻塞呼叫。
您可以推遲閱讀,直到命令完成。
首先,創建命令:
commands = Array.new(3) { |i| Open3.popen2("sleep 5; echo hello from #{i}") }
然后,等待每個命令完成:
commands.each { |stdin, stdout, wait_thr| wait_thr.join }
最后,收集輸出并關閉 IO 流:
commands.each do |stdin, stdout, wait_thr|
puts stdout.read
stdin.close
stdout.close
end
輸出:(5秒后)
hello from 0
hello from 1
hello from 2
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/440696.html
