ruby マルチスレッド を many core の CPU で動かしても 100% で止まる。
とまるんですよ。i7 のCPUリソース余って勿体ない。
GIL ( global interpreter lock )
ruby がYARVで Global Interpreter Lock の中で動作するので、マルチスレッドでもメニーコアを使い切れない。
CPU 使用率が100%で頭打ち
4コアあって400%まで出せるとしても、100%でとまる。
マルチスレッドといっても、Ruby(MRI)で同時に実行されるスレッドは1本なんですよ。
スレッドが同時に動いてるということはない。1つが動くとほかは止まってる。
主に、IOブロックで実行コンテキストを切り替える。なので、
使い切るには?
- jruby を使う
- rubinius を使う
- 小さいコマンドに分割する。
jruby を使えば、GILの影響を受けずに、マルチスレッドでマルチコアを使い切れることを確認。
マルチスレッドでも、ロックなどをしっかりしないとダメ
ここをさらっと読んだけど、Atomicにちゃんとスレッドセーフしないと
http://www.jstorimer.com/blogs/workingwithcode/8085491-nobody-understands-the-gil
サンプル
array = [] 5.times.map do Thread.new do 1000.times do array << nil end end end.each(&:join) puts array.size
takuya@~/Desktop$ ruby test.rb 5000 takuya@~/Desktop$ jruby test.rb 4727
スレッドで同時実行されて壊れる。
mutex を使って、スレッドセーフにしたら。。。
マルチスレッドで変数が壊れるので、ちゃんとSynchronizedにしてみたら・・・
require 'thread' require 'monitor' array = [] m = Mutex.new 5.times.map do Thread.new do 1000.times do m.synchronize do array << nil end end end end.each(&:join) puts array.size
takuya@~/Desktop$ for i in {1..100}; do jruby test.rb ;done; 5000 5000 5000 5000 5000 5000 5000 5000 5000
壊れない。
むしろ、sync しないで動くMRI の方が気持ち悪い気もしてきた。
とにかく上限100%
MRIはスレッド使い切れないことが分かった。
しっかりスレッドセーフなプログラムを書いて試さないと、jRubyですらどう動くか予想がつかない。・・・怖い。
解決策は小さいプロセスを大量にexec することかも
xargs てきに小さいプロセス起動しまくるってのが良いのかも。