【问题标题】:Fork a child process, and capture any stdout and stderr?分叉一个子进程,并捕获任何标准输出和标准错误?
【发布时间】:2020-08-18 09:33:21
【问题描述】:

我下面的代码示例运行一个命令,例如 ls <file> 并捕获 stdout 和 stderr(以及进程退出状态)。

但是,例如,如果命令挂起,那么 ruby​​ 程序将“卡住”,等待命令完成(例如,如果运行 sleep,则可以看到这一点)。

为了避免这种可能性,我认为我需要做的是fork 一个子进程,(所以任何“卡住”的子进程都不会让 ruby​​ 程序“等待”)。

但是,我不确定如何从分叉的子进程中捕获标准输出和标准错误,这是否可能?

(出于原因我还希望能够在 ruby​​ 标准库中执行此操作,并且不依赖任何额外的 gem/s。 此外,这仅适用于 ruby​​,not rails )

编辑:帮助澄清 - 试图了解是否有办法分叉子进程,(因此在子进程完成之前不会阻塞),仍然让 ruby​​ 程序在子进程退出时捕获 stdout、stderr .

#!/bin/env ruby

require 'open3'
require 'logger'

logger = Logger.new('./test_open3.log')
files = ['file1','file2','file3']

files.each do |f|
  stdout, stderr, status = Open3.capture3("ls #{f}")
  logger.info(stdout)
  logger.info(stderr)
  logger.info(status)
end

【问题讨论】:

  • 但是 stdoutstderrstatus 在孩子完成之前不能有有意义的值。
  • Open3.capture3 将阻塞直到孩子完成。
  • @twenty20,你能告诉我们你的程序在做什么但不起作用吗?
  • @MichaelChaney 我认为关键是 OP 想要一种方法来阻止直到孩子完成。
  • @twenty20,您也可以使用线程来捕获输出。您的程序将不再是连续的,因为子进程将继续与您的主进程一起运行。您必须想办法知道子流程何时完成并收获/使用输出。这是一种非常不同的编程方式。

标签: ruby fork parent-child stdout stderr


【解决方案1】:

按照 cmets 中使用线程的建议,我发现这给了我想要的东西:

#!/bin/env ruby

require 'open3'
require 'logger'
require 'thread'

logger = Logger.new('./test_threads_open3.log')
files = ['file1','file2','file3']
threads = []

files.each_with_index do |f, i|
  threads << Thread.new(f, i) do
    puts "Thread #{i} is running"
    stdout, stderr, status = Open3.capture3("ls #{f}")
    logger.info(stdout)
    logger.info(stderr)
    logger.info(status)
   end
 end
threads.each { |t| t.join }

这会创建一个线程数组,每个线程都有代码块,然后最后一行,数组中的每个线程都运行。

它可能需要一些额外的代码来管理和限制一次可以运行的线程数,以便更安全,也许可以通过使用队列/工作者功能。

(本帖还涉及到join方法的话题-Thread.join blocks the main thread)

【讨论】:

    猜你喜欢
    • 2012-09-17
    • 2018-11-25
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 2010-10-29
    • 2020-10-18
    相关资源
    最近更新 更多