Help us understand the problem. What is going on with this article?

Parallelのマルチプロセスでハマったこと

More than 1 year has passed since last update.

Parallelのマルチプロセスでハマったこと

マルチプロセスにおいて子プロセスは親プロセスの変数に影響を及ぼさない

まず、以下のようなマルチスレッドで実行されるコードをみましょう。

Rubyコード
multi_threads.rb
require 'parallel'
files = [1, 2, 3, 4, 5, 6, 7 ,8, 9 ,10 ,11, 12, 13]
@array = []
Parallel.each(files, :in_threads=>10) {|x|
  @array.push(x)
}

puts @array
結果
[1, 2, 4, 3, 5, 7, 6, 8, 9, 11, 13, 12, 10]

上記のものをマルチプロセスで実行するようにしようとして、 :in_threads のところを単純に :in_processes に変更しました。そうすると。。

Rubyコード
multi_processes.rb
require 'parallel'
files = [1, 2, 3, 4, 5, 6, 7 ,8, 9 ,10 ,11, 12, 13]
@array = []
Parallel.each(files, :in_processes=>10) {|x|
  @array.push(x)
}

puts @array
結果
[]

何にも出力されませんでした!!!なんだって!!!

理由

Parallelでは子プロセスをforkして子プロセス内でロジックを遂行していきますが、同じ変数であっても親プロセスと各子プロセスの変数はメモリ上別領域にあるためです。
スクリーンショット 2017-07-11 21.13.42.png

以下のコードを実行して結果を見ればわかるように、子プロセスで累積した結果は、親プロセスに何の影響も及ぼしません。

コード
multi_processes_test.rb
require 'parallel'
files = [1, 2, 3, 4, 5, 6, 7 ,8, 9 ,10 ,11, 12, 13]
@array = []
puts "parent pid: #{$$}"
Parallel.each(files, :in_processes=>10) {|x|
  puts "pid:#{$$} #{x} #{@array}"
  @array.push(x)
}
puts "parent pid:#{$$} #{@array}"
結果
parent pid: 65100
pid:65101 1 []
pid:65102 2 []
pid:65104 3 []
pid:65106 4 []
pid:65101 5 [1]
pid:65110 7 []
pid:65103 8 []
pid:65104 9 [3]
pid:65102 12 [2]
pid:65106 13 [4]
pid:65105 10 []
pid:65107 11 []
pid:65109 6 []
parent pid:65100 []

対処方法

Parallel.map を使用することです。

Rubyコード
improved_multi_processes.rb
require 'parallel'
files = [1, 2, 3, 4, 5, 6, 7 ,8, 9 ,10 ,11, 12, 13]
@array = []
@array = Parallel.map(files, :in_processes=>10) {|x|
  x
}

puts @array
結果
[1, 2, 4, 3, 5, 7, 6, 8, 9, 11, 13, 12, 10]

来た!!

このロジックいける理由は、子プロセスが死ぬときに、その戻り値を親プロセスに伝え、親プロセスがそれを収集して結果を返すためだそうです。。(僕もロジックはみてないので自身はありませんwww)

以上です。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away