收集Ruby Parallel Gem的结果

pca*_*ca2 3 ruby parallel-processing fork

Ruby的Parallel gem似乎非常强大,但是我在使用它来构建集合时遇到了麻烦.

将进程设置为0,采用以下示例:

[174] pry(main)> @array = []
=> []
[175] pry(main)> Parallel.each(1..10, :in_processes=>0) {|x| @array.push(Random.rand(10))}
=> 1..10
[176] pry(main)> @array
=> [7, 3, 5, 6, 1, 5, 4, 4, 5, 1]
Run Code Online (Sandbox Code Playgroud)

但是当我们将流程设置为2时:

[177] pry(main)> @array = []
=> []
[178] pry(main)> Parallel.each(1..10, :in_processes=>2) {|x| @array.push(Random.rand(10))}
=> 1..10
[179] pry(main)> @array
=> []
Run Code Online (Sandbox Code Playgroud)

显然,这甚至不接近构建随机值数组的最佳方法,我想要的是,当有多个进程时循环结束后,附加到@array的值不存在.这是一个范围问题还是我误解了叉子是如何工作的?

Chr*_*ald 6

并行的默认模式通过分支您的流程并在子流程中完成工作(这是IMO,一个巨大的黑客)在幕后工作.子进程不会对父进程的内存具有写访问权限; 在孩子中所做的更改不会持久存在于父母身上.

您只能通过gem的工具与您的父流程进行通信,这些工具可以捕获孩子的返回值.Parallel.map提供了一种机制,通过该机制,传入的数据在父节点封送,然后在子节点上解组,处理,然后结果被封送并传递回父节点,并收集到结果数组中.当分叉的孩子死亡时,任何过去的东西都会被"扔掉".

请考虑使用线程(并正确地同步对共享变量的访问).如果您需要多核并发(即,您正在进行未在IO上阻止的并行工作),您应该考虑JRuby,它没有GIL并且可以本机地并行执行多个Ruby线程.

  • 我可以确认用 `in_threads` 切换 `in_processes` 似乎对这个例子有效,谢谢 (2认同)
  • 您应该使用互斥锁同步对并行循环内“@array”的访问;由于 GIL,它现在可以工作,但是数组访问不是原子的,并且在更高版本的 Ruby 中最终可能会得到非常奇怪的结果。 (2认同)