从分叉进程返回数据

gro*_*ser 24 ruby fork process

如果我做

Process.fork do 
  x 
end 
Run Code Online (Sandbox Code Playgroud)

我怎么知道x返回了什么(例如true/fase/string)?

(写入文件/数据库不是一种选择......)

Yeh*_*atz 31

我们实际上只需要在Rails隔离测试中处理这个问题.我在博客上发布了一些相关信息.

基本上,您要做的是在父级和子级中打开管道,并让子级写入管道.这是在子进程中运行块的内容并获取结果的简单方法:

def do_in_child
  read, write = IO.pipe

  pid = fork do
    read.close
    result = yield
    Marshal.dump(result, write)
    exit!(0) # skips exit handlers.
  end

  write.close
  result = read.read
  Process.wait(pid)
  raise "child failed" if result.empty?
  Marshal.load(result)
end
Run Code Online (Sandbox Code Playgroud)

然后你可以运行:

do_in_child do
  require "some_polluting_library"
  SomePollutingLibrary.some_operation
end
Run Code Online (Sandbox Code Playgroud)

请注意,如果在子级中执行require,则无法访问父级中的该库,因此无法使用此方法返回该类型的对象.但是,您可以返回两者中可用的任何类型.

还要注意的是这里很多(详细read.close,Process.wait2(pid))大都是看家的细节,所以如果你使用这个有很多你应该移到了这一点,到公共图书馆,你可以重复使用.

最后请注意,这不适用于Windows或JRuby,因为它们不支持分叉.


gro*_*ser 11

感谢所有的答案,我启动并运行了我的解决方案,仍然需要看看如何处理非分叉环境,但现在它的工作:)

read, write = IO.pipe
Process.fork do
  write.puts "test"
end
Process.fork do
  write.puts 'test 2'
end

Process.wait
Process.wait

write.close
puts read.read
read.close
Run Code Online (Sandbox Code Playgroud)

你可以在@ parallel_specs Rails插件中看到它


gro*_*ser 10

我将沿途发现的所有解决方案(用户退出+管道缓冲区等其他问题)包装到ruby parallel gem中.现在它很简单:

results = Parallel.map([1,2,3],:in_processes=>4) do |i|
  execute_something(i)
end
Run Code Online (Sandbox Code Playgroud)

要么

results = Parallel.map([1,2,3],:in_threads=>4) do |i|
  execute_something(i)
end
Run Code Online (Sandbox Code Playgroud)

  • 你可以在这里作为参数传递对象甚至类吗?我真的可以使用一种方法来分叉一个进程并将整个环境传递给它. (2认同)