スレッド化で早くなるのか試してみた
rubyのスレッド数を制御して処理するエントリを書いた⇛ruby スレッドの同時実行数を制御する - それマグで!
じゃぁ、実際に早くなるのか実験してみよう。
画像ファイル55枚で実験
画像の縮小処理とGPS情報削除をサンプルにやってみる
- bashで単純なコマンド起動をする
- コマンド起動スレッド5本まで
- コマンド起動スレッド10本までにする
- 1ファイルに1スレッド大量スレッド起動
画像ファイルはiphone5の写真2.4Mbytes が55枚。*1
実行マシンはMacbook Air Mid2011 Core i5 mem 4GB
単純なbashで起動
一番単純な *.jpg を引数にするパターン。これはbashが1ファイルずつ起動していきます。
takuya@air:~/Desktop$ time mogrify -strip -resize 800 *.jpg real 0m32.233s user 0m31.022s sys 0m1.074s
この結果の秒数をベースに考えます。
rubyで5スレッドで制御
ruby で5スレッド(5個のサブプロセス起動)で処理
takuya@air:~/Desktop$ time ./test5.rb *.jpg real 0m20.595s user 1m4.805s sys 0m5.616s
期待通り早くなる
require './my_patched_thread.rb' Thread.max_concurrent=5 ARGV.map{|f| Thread.new{ `mogrify -strip -resize 800 '#{f}' ` } }.each{|t| t.join }
では、10スレッドで制御
takuya@air:~/Desktop$ time ./test.rb *.jpg real 0m19.787s user 1m2.683s sys 0m5.265s
Thread.max_concurrent=10 #以下同じ
10スレッドでもそんなに早くならない。
スレッド化しない場合
takuya@air:~/Desktop$ time ./test_no_thread.rb *.jpg real 0m35.574s user 0m32.048s sys 0m3.159s
ソースはこちら
ARGV.map{|f| `mogrify -strip -resize 800 '#{f}' ` }
ファイル全部をスレッド起動
1ファイルに1スレッドを割り当てて、スレッドバンバン起動した
これは、予想以上に遅かった。
takuya@air:~/Desktop$ time ./test.rb *.jpg real 2m28.569s user 0m57.969s sys 0m43.182s
55ファイルなので、55スレッドが起動して、55プロセスが同時にファイルに読み込みと書込するので、やたら遅い
ソースはこちら
ARGV.map{|f| Thread.start{ `mogrify -strip -resize 800 '#{f}' ` } }
まとめ
処理 | real | user | sys |
---|---|---|---|
bashのみ | 0m32.233s | 0m31.022s | 0m1.074s |
スレッド化無し | 0m35.574s | 0m32.048s | 0m3.159s |
5スレッド | 0m20.595s | 1m4.805s | 0m5.616s |
10スレッド | 0m19.787s | 1m2.683s | 0m5.265s |
全部スレッド化 | 2m28.569s | 0m57.969s | 0m43.182s |
結論
スレッド化効果ある。ruby のスレッドはディスクIO待ちで切り替わるので、そんなに早くならないかと思ったけど、それなりには早くなる。
単純にThread.new{コマンド起動}の場合は、ファイル受けて、スレッドでコマンド起動したので、ファイル数分コマンド起動するとそれだけマシンのディスクIOを奪い合って、リソース不足になって大変みたい。
でも、スレッド数制御のために面倒なコード*2が必要になるので。前エントリのやり方はそれなりに、使えるんじゃないか。
単純に、これを書くだけに収まるの、明確で嬉しい。
Thread.max_concurrent=5 ARGV.map{|f| Thread.new{ `mogrify -strip -resize 800 '#{f}' ` } }.each{|t| t.join}
スレッドは常時動いてる前提なので、こういう使い方は、「んー」って感じだけどスレッドをキューにためて、準備のできたものから順に起動するって使い方をやりたい場面は多いしスレッド作るときでも、単純に数本を並列化したいことが多いので、結構使えそうです。