LoginSignup
0
0

More than 3 years have passed since last update.

Rubyのat_exitとParallel(マルチプロセス処理)でおかしなことを起こしてしまった話

Last updated at Posted at 2019-05-10

at_exitとは

RubyにはKernel#at_exitというメソッドがあります。
これは、Rubyの処理の終了時に実行する処理を追加出来るようなメソッドで、使い方によっては非常に便利に使えるものです。
(よく調べてないですが結構色々なGemで使用されているらしいです)

Parallelとは

Rubyにおいてマルチプロセス/スレッドの処理を簡単に使えるようにしてくれるGemです。
Rubyで並列処理を行いたい場合はよく使うと思います。

今回起きちゃった問題

at_exitとParallelによるマルチプロセス処理を同時に使ったことで、おかしな挙動が置きました。

具体的にはこんな感じ↓

test.rb
at_exit do
  puts "run at_exit!"
end

Parallel.each(1..4, in_processes: 4) do |num|
  sleep num
  puts "sleep done! #{num}"
end

このファイルを実行した結果が↓

$ ruby at_exit_and_multi_process_test.rb
sleep done! 1
run at_exit!
sleep done! 2
run at_exit!
sleep done! 3
run at_exit!
sleep done! 4
run at_exit!
run at_exit!

at_exitが5回も走ってる!!:fearful:

基本的にat_exitを使用する場合、処理の最後に1回だけ走って欲しいという感じの使い方をすると思うのですが、これだとよろしくないですね。

原因はまあなんとなく察しがつくと思います。
at_exit内の処理はrubyの処理の終了時にフックされるわけですが、その「rubyの処理の終了」が、各子プロセスで発生してしまい、親プロセスの状態をforkしている子プロセスでも同じat_exitの処理が走ってしまったという話ですね。(多分)
さらに親プロセスの終了分まで含めて5回も走ってしまったわけです。

ちなみにマルチスレッド処理では問題なく動作し、結果は下記のようになります↓

$ ruby at_exit_and_multi_thread_test.rb
sleep done! 1
sleep done! 2
sleep done! 3
sleep done! 4
run at_exit!

多分at_exitとParallelを同時に使用している人があまりいないのか、ググってもあまりヒットしなかったので記事にしてみました。

考えてみれば全然わかることではあるのですが、特に意識せずにやってしまって挙動がおかしくなってしまったので皆様ご注意を:wave:

参考

https://docs.ruby-lang.org/ja/latest/method/Kernel/m/at_exit.html
https://techracho.bpsinc.jp/hachi8833/2018_05_22/56171
https://qiita.com/sekido-ts/items/5dc9c88d877bb2a1df0b
https://qiita.com/Kohei909Otsuka/items/26be74de803d195b37bd

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0