首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >非阻塞背板

非阻塞背板
EN

Stack Overflow用户
提问于 2022-03-10 08:14:41
回答 1查看 75关注 0票数 1

我想以一种非阻塞(异步)的方式从Ruby运行多个耗时的shell命令。

我希望将选项传递给命令,接收Ruby中的输出,(理想情况下)处理错误。

下面的脚本自然需要15秒才能执行:

test.rb

代码语言:javascript
复制
3.times do |i|
  puts `sleep 5; echo #{i} | tail -n 1` # some time-consuming complex command
end
代码语言:javascript
复制
$ /usr/bin/time ruby test.rb
0
1
2
       15.29 real         0.13 user         0.09 sys

使用线程,它显然可以并行执行,它只需5秒,就像预期的那样:

代码语言:javascript
复制
threads = []

3.times do |i|
  threads << Thread.new {
    puts `sleep 5; echo #{i} | tail -n 1`
  }
end

threads.each {|t| t.join() }
代码语言:javascript
复制
$ /usr/bin/time ruby test.rb
2
0
1
        5.17 real         0.12 user         0.06 sys

但这是最好的方法吗?还有别的办法吗?

我也使用Open3.popen2编写了文章,但这似乎需要15秒来执行,如第一个示例所示(除非封装在线程中):

代码语言:javascript
复制
require 'open3'

3.times do |i|
  Open3.popen2("sleep 5; echo #{i} | tail -n 1") do |stdin, stdout|
    puts stdout.read()
  end
end

文献资料描述了“块表单”和“非块表单”,但是这个“块”指的是匿名函数,与并发性无关,对吗?

只有Open3类才能阻止执行吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-10 10:17:14

代码的问题是stdout.read是一个阻塞调用。

您可以将读取推迟到命令完成为止。

首先,创建以下命令:

代码语言:javascript
复制
commands = Array.new(3) { |i| Open3.popen2("sleep 5; echo hello from #{i}") }

然后,等待每个命令完成:

代码语言:javascript
复制
commands.each { |stdin, stdout, wait_thr| wait_thr.join }

最后,收集输出并关闭IO流:

代码语言:javascript
复制
commands.each do |stdin, stdout, wait_thr|
  puts stdout.read
  stdin.close
  stdout.close
end

输出:(5秒后)

代码语言:javascript
复制
hello from 0
hello from 1
hello from 2
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71420764

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档