Ruby - スレッドで並列処理!

Updated:


Ruby でスレッドを使用して処理を並列化&高速化する方法についての記録です。

単純に複数の処理を複数のスレッドにして処理する方法もありますが、今回はより実用的な方法を試行してみました。

実際には、スレッドとのデータのやりとりのためにキューを使用しています。

「キュー」とは、先入れ先出し(FIFL:First In First Out) 構造の概念です。 同様に、後入れ先出し (LIFO: Last In First Out; FILO: First In Last Out) 構造の「スタック」という概念もあります。

以下、サンプルスクリプトです。

作業記録

0. 前提条件

  • Cygwin 1.7.15
  • Ruby 1.9.3-p194

1. サンプルスクリプト作成

  • ループ処理で作成されたデータをスレッドで使用するためにキューに格納。
  • スレッドを同時に大量に実行すると処理が重くなる可能性があるため、同時に実行するスレッドの最大数を設定。
  • 各スレッド側では、ループ処理でキューに格納された値を取得して処理。
  • 各スレッドはランダム時間スリープして画面出力しているだけ。

以下の例では、スレッドは同時に10個処理されるようにしています。

【 ファイル名: test_thread.rb 】

require 'thread'

class TestThread
  max_cnt   = 10         # 同時に処理するスレッドの最大数
  obj_queue = Queue.new  # キューのインスタンス化

  # スレッドで処理
  ary_threads = []
  max_cnt.times do
    ary_threads << Thread.start do
      while !obj_queue.empty?
        var = obj_queue.pop
        t = rand(0)
        sleep t
        printf( "Thread %03d ( %10.8f ) \n", var, t )
      end
    end
  end

  # キュー
  ( 1..100 ).each do |i|
    obj_queue.push( i )
  end

  # スレッド完了待ち
  ary_threads.each { |th| th.join }
end

2. サンプルスクリプト実行

作成した Ruby スクリプトを実行してみる。 実行される各スレッドの処理時間が異なるので、当然キューから取り出した順番どおりにはならないです。 しかし、同時に10スレッドずつ処理を行うので、全体の処理時間が単純に1つずつ処理するより短くなります。 実際に、複雑な処理で試してみると処理が高速化されることが分かると思います。

$ ruby test_thread.rb
Thread 008 ( 0.01422097 )
Thread 010 ( 0.34864313 )
Thread 003 ( 0.38478702 )
Thread 006 ( 0.43588485 )
Thread 012 ( 0.18279647 )
Thread 002 ( 0.56489740 )
Thread 013 ( 0.29721758 )
Thread 007 ( 0.73026878 )
Thread 005 ( 0.76804741 )
Thread 004 ( 0.78217592 )
         :
====< 途中省略 >==== 
         :
Thread 099 ( 0.07962445 )
Thread 090 ( 0.49958674 )
Thread 089 ( 0.57727429 )
Thread 097 ( 0.35715680 )
Thread 084 ( 0.99318709 )
Thread 100 ( 0.41874839 )
Thread 093 ( 0.66151962 )
Thread 095 ( 0.59846617 )
Thread 096 ( 0.61467788 )
Thread 098 ( 0.64307587 )

当方の場合、Webサイトから情報を取得する処理でスレッド・キューを使用して、かなり高速化されました。 約30分の処理が約6分、約100分の処理が約20分、と「5分の1」程にできました。

以上。





 

Sponsored Link

 

Comments