Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 从分叉进程返回数据_Ruby_Process_Fork - Fatal编程技术网

Ruby 从分叉进程返回数据

Ruby 从分叉进程返回数据,ruby,process,fork,Ruby,Process,Fork,如果我这样做 Process.fork do x end 我如何知道x返回了什么(例如true/fase/string) (写入文件/数据库不是选项…根据文档: 如果指定了块,则该块将在子流程中运行,子流程将以零状态终止 因此,如果用块调用它,它将返回0。否则,它的功能基本上与Unix上的fork()系统调用相同(父进程接收新进程的PID,子进程接收nil)。两个Unix进程之间的fork通信主要是返回码,仅此而已。但是,您可以在两个进程之间打开一个filedescriptor,并通

如果我这样做

Process.fork do 
  x 
end 
我如何知道x返回了什么(例如true/fase/string)


(写入文件/数据库不是选项…

根据文档:

如果指定了块,则该块将在子流程中运行,子流程将以零状态终止


因此,如果用块调用它,它将返回0。否则,它的功能基本上与Unix上的
fork()
系统调用相同(父进程接收新进程的PID,子进程接收
nil
)。

两个Unix进程之间的fork通信主要是返回码,仅此而已。但是,您可以在两个进程之间打开一个filedescriptor,并通过该filedescriptor在进程之间传递数据:这是正常的Unix管道方式


如果要传递Marshal.dump()和Marshal.load()值,则可以轻松地在这些Ruby进程之间传递Ruby对象。

如果子进程只需要一小段Ruby代码,则可以使用共享内存来传递。类似于以下的方法将起作用:

str = 'from parent'

Thread.new do
  str = 'from child'
end

sleep(1)

puts str    # outputs "from child"
然而,并发性可能非常棘手,并且以这种方式访问共享内存是一个很大的原因——任何时候,当你有一个变量,而另一个进程可能会从你下面改变它时,你都应该非常小心。或者,您可以使用管道,它更麻烦,但对于除最琐碎的代码之外的任何代码都可能更安全,还可以用于运行任何任意命令。下面是一个例子,直接来自IO.popen的rdoc:

f = IO.popen("uname")
p f.readlines     # outputs "Darwin", at least on my box  :-)

事实上,我们只是需要在一个小时内处理这个问题。我发了一些关于它的帖子

基本上,您要做的是在父级和子级中打开一个管道,并让子级写入管道。下面是一种在子进程中运行块内容并返回结果的简单方法:

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
然后你可以跑:

do_in_child do
  require "some_polluting_library"
  SomePollutingLibrary.some_operation
end
请注意,如果在子对象中执行require,则无法访问父对象中的该库,因此无法使用此方法返回该类型的对象。但是,您可以返回在这两种语言中都可用的任何类型

还要注意,这里的很多细节(
read.close
Process.wait2(pid)
)都是内务处理细节,所以如果您经常使用这些细节,您可能应该将其移到可以重用的实用程序库中


最后,请注意,这在Windows或JRuby上不起作用,因为它们不支持分叉。

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


您可以在操作中看到它@

我将在过程中发现的所有解决方案(一些其他问题,如用户退出+管道缓冲区)都打包到了。现在,它非常简单:

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


是的,您可以创建一个子流程来执行内部的块

我建议:

当然,它可以防止副作用:

arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]
arr=['foo']
啊,福克!{arr[“foo”,“FUU”]
arr#=>[“foo”]

这有助于获取“x”返回的内容吗?子进程在单独的进程中运行(显然),因此要获取任何“x”的值是的,您可能必须通过套接字、管道或类似的方式进行通信。我怀疑您是否可以,例如,在块内设置反映在块外的变量,因为子进程有单独的内存,等等。您看到我在回答中提供的隔离测试链接了吗?它处理分叉和非分叉环境,以及可能已经完成了您需要的所有操作。您可以在这里传递对象,甚至类作为参数吗?我真的可以使用一种方法来分叉一个进程,并将整个环境传递给它。
results = Parallel.map([1,2,3],:in_threads=>4) do |i|
  execute_something(i)
end
Aw.fork! { 6 * 7 } # => 42
arr = ['foo']
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"]
arr # => ["foo"]