かとじゅんの技術日誌

技術の話をするところ

Scalaでアクターではなくスレッドを操る

Scalaといえば並行処理、並行処理といえばアクター。ということだけど、そこまで大袈裟ではなくサクっとスレッドを起こしたい時はどうしたらよいか。

「プログラミングScala」のP220に「9.4.1 その場限りのスレッド」にopsオブジェクトのspawnメソッドが紹介されています。

import scala.concurrent.ops._

object SpawnExample {
  def main(args: Array[String]) {
    println("start")
    spawn {
      println("async")
    }
  }
}

spawnで指定したブロックがスレッドで実行されます。こんなに簡単に書けてよいのか!よいのですw
spawnメソッド内部の擬似コードはこんな感じ。

def spawn(r: => Unit) = {
  val t = new Thread() {
    override def run() = r
  }
  t.start()
}

rは名前渡しパラメータ。rを"名前渡し"ではなく通常の関数リテラルで"値渡し"で記述すると以下のようになる

def spawn(r: () => Unit) = {

しかし、以下のような記述はできなく

spawn( println("abc") )

このような冗長な記述になってしまう。ので、そのまま関数やブロックを渡したい場合名前渡しで行う。

spawn( () => println("abc") )

だから、()をなくした名前渡しパラメータを利用する。

def spawn(r: => Unit) = {

プログラミングScala

プログラミングScala


オブジェクト指向プログラマが次に読む本 Scalaで学ぶ関数脳入門」P104で値渡しと名前渡しの違いについて記述があります。名前渡しは遅延評価ということですね。

値渡しでは、ます引数の式を評価して、関数内の対応する変数をその評価値でパインドします。一方、名前渡しでは、関数の呼び出し時点では引数はまったく評価されず、関数内で参照された時点ではじめて評価されます。複数回参照が行われた場合は、その都度再評価が行われます。

オブジェクト指向プログラマが次に読む本 ?Scalaで学ぶ関数脳入門

オブジェクト指向プログラマが次に読む本 ?Scalaで学ぶ関数脳入門


concurrentも普通に使えます。

import java.util.concurrent

class GetThreadId extends Runnable {
  def run {
    println("thread id = " + currentThread.getId)
  }
}
val pool = Executors.newFixedThreadPool(5)
for (i < - 1 to 10) {
  pool.execute(new GetThreadId)
}

Javaらしさを残したまま、すっきりとしたコードを書けるのがScalaの特徴ですね。