Hatena::Groupsubtech

#生存戦略 、それは

-> 11 { 09 / 27 }

Ruby で並列実行処理を簡単に書く

20:31 | はてなブックマーク - Ruby で並列実行処理を簡単に書く - #生存戦略 、それは

Ruby は 1.8 だとグリーンスレッドだし、1.9 でも Giant VM lock のためネイティブスレッドの実行は一つのため、マルチコアを生かした処理をかんたんに書くのがいささか面倒だったりしますね。

で、 parallel というライブラリを使うと fork を使って抽象化してくれるのですごく簡単にかける。

ふつうに Parallel#each/map の中で並列処理させたいコードを書くだけ。戻り値が #map なら取得できる。 以下は zlib で gzip 圧縮させた結果。

require 'rubygems'
require 'parallel'
require 'pathname'
require 'benchmark'
require 'zlib'

compress_files = lambda {|file|
  Zlib::GzipWriter.open(file.realpath.to_s + '.gz') {|gz| gz.puts file.read }
}

puts "#{Parallel.processor_count} procesor(s)"

files = Pathname.glob('*.log')

Benchmark.bm do |x|
  x.report('normal') { 
    files.each &compress_files
  }
  x.report('thread') { 
    Parallel.each(files, :in_threads => Parallel.processor_count, &compress_files)
  }
  x.report('fork') { 
    Parallel.each(files, &compress_files)
  }
end

CPU が i7 の環境(2コア・仮想4スレッド)では

4 procesor(s)
      user     system      total        real
normal 16.740000   2.100000  18.840000 ( 19.154235)
thread 19.550000   2.350000  22.050000 ( 24.297111)
fork  0.010000   0.040000  27.890000 ( 12.871694)

と、19秒強 -> 13秒弱と簡単に速度を上げることができた。みんな大好き parallel_test も内部では parallel を利用している。べんり。

あと Thread での並列処理も抽象化も簡単に書けるので、select で IO 待ちするような処理も直感的に書いてスピードアップできる。

require 'rubygems'
require 'parallel'
require 'open-uri'

urls = (1..10).map {|i| "http://example.com/?query=#{i}" }
results = Parallel.map(urls, :in_threads => 10) {|url|
  puts "download: #{url}"
  body = open(url).read
  puts "downloaded: #{url}"
  body
}

Thread で 10並列でダウンロードで全部結果が帰ってきたら次、みたいな。

download: http://example.com/?query=1
download: http://example.com/?query=2
download: http://example.com/?query=3
download: http://example.com/?query=4
download: http://example.com/?query=5
download: http://example.com/?query=6
download: http://example.com/?query=7
download: http://example.com/?query=8
download: http://example.com/?query=9
download: http://example.com/?query=10
downloaded: http://example.com/?query=2
downloaded: http://example.com/?query=5
downloaded: http://example.com/?query=4
downloaded: http://example.com/?query=1
downloaded: http://example.com/?query=9
downloaded: http://example.com/?query=7
downloaded: http://example.com/?query=3
downloaded: http://example.com/?query=8
downloaded: http://example.com/?query=10
downloaded: http://example.com/?query=6

sora_hsora_h2011/09/27 22:27fork楽でいいよね
(rubyのtest/unitのアレはWinなんとかとかいう邪悪なアレの所為でIO.popen (spawn) とかごにょごにょしてる)

secondlifesecondlife2011/09/27 22:35windows 忘れれば簡単だし幸せになれるね!!!

mrknmrkn2011/09/28 14:47> windows 忘れれば簡単だし幸せになれるね!!!
これを irc の #ruby-ja で呟くと、漏れなく機関からの手先に締め上げられます。

secondlifesecondlife2011/09/28 15:12ヒイ恐ろしい…

m_sekim_seki2011/09/30 07:32rinda_evalの方がイケメン