2012年2月11日土曜日

ScalaのActorとsleep

ScalaのActorの中でThread.sleepを使っていたら、どうも平行に処理されていないような気がして調べてみました。

 例えば、javaのThreadを使って以下のようなコードを実行する。
      1 to 10 map( n => (new Thread() {
 override def run = {
   println("start "+n)
   Thread.sleep( 3000 )
   println("done "+n)
 }
      }).start )
結果の出力は、以下のように、ほぼ同時に10個のスレッドがスタートして、 3秒後にそれぞれ終了する。
これは、予想通り。
start 10
start 4
start 6
start 2
start 3
start 8
start 9
start 7
start 1
start 5
done 10
done 4
done 6
done 2
done 3
done 8
done 9
done 7
done 1
done 5
これをActorを使って書き換える。
      1 to 10 map( n => Actor.actor {
 println("start "+n)
 Thread.sleep( 3000 )
 println("done "+n)
      })
このコードを実行した結果。
start 1
start 6
start 8
start 7
start 3
start 5
start 2
start 4
done 1
done 6
done 8
start 9
start 10
done 3
done 7
done 4
done 2
done 5
done 9
done 10
この結果をみると、最初の8個のスレッドは、ほぼ同時にスタートしているのがわかるが、 残りの2つは、最初にスタートしたスレッドが終わるのを待ってから、3秒後にそれぞれスタートしている。 

なぜ? 

どうやらこれはActorのプールに関係しているらしい。
 詳しくは分からないが、Thread.sleepを使った場合、 並列に実行できるのは、CPUのスレッド数のみのようだ。
それ以上に、並列に実行したいので、Thread.sleepを使わずに、 receiveWithinを使ったらうまくいった。
      1 to 10 map( n => Actor.actor {
 println("start "+n)
 Actor.self.receiveWithin( 3000 ) { case TIMEOUT => {}}
 println("done "+n)
      })
仕方ないので、この方法でやるかなぁ。

0 件のコメント:

コメントを投稿