ScalaのActorライブラリを見ていると、たまにDebugというクラスを見かけます。例えば…
Code from Reactor.scala... version 2.9.0.1
/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2005-2011, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ package scala.actors import scala.actors.scheduler.{DelegatingScheduler, ExecutorScheduler, ForkJoinScheduler, ThreadPoolConfig} import java.util.concurrent.{ThreadPoolExecutor, TimeUnit, LinkedBlockingQueue} private[actors] object Reactor { val scheduler = new DelegatingScheduler { def makeNewScheduler: IScheduler = { val sched = if (!ThreadPoolConfig.useForkJoin) { // default is non-daemon val workQueue = new LinkedBlockingQueue[Runnable] ExecutorScheduler( new ThreadPoolExecutor(ThreadPoolConfig.corePoolSize, ThreadPoolConfig.maxPoolSize, 60000L, TimeUnit.MILLISECONDS, workQueue, new ThreadPoolExecutor.CallerRunsPolicy)) } else { // default is non-daemon, non-fair val s = new ForkJoinScheduler(ThreadPoolConfig.corePoolSize, ThreadPoolConfig.maxPoolSize, false, false) s.start() s } Debug.info(this+": starting new "+sched+" ["+sched.getClass+"]") sched } } …省略…
つまり、この部分ですね。
Debug.info(this+": starting new "+sched+" ["+sched.getClass+"]")
なんか、Actor用のデバッグクラスっぽいのですが、普段はActorを使っても何も言ってくれません。どうなっているのか?ってことで、Debugクラスを見てみましょう。正確には、Debugオブジェクトですが。
Code from Debug.scala... version 2.9.0.1
/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2005-2011, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ package scala.actors /** * Provides methods for generating debugging output. * * @author Philipp Haller */ object Debug extends Logger("") {} private[actors] class Logger(tag: String) { private var lev = 2 def level = lev def level_= (lev: Int) = { this.lev = lev } private val tagString = if (tag == "") "" else " ["+tag+"]" def info(s: String) = if (lev > 2) System.out.println("Info" + tagString + ": " + s) def warning(s: String) = if (lev > 1) System.err.println("Warning" + tagString + ": " + s) def error(s: String) = if (lev > 0) System.err.println("Error" + tagString + ": " + s) def doInfo(b: => Unit) = if (lev > 2) b def doWarning(b: => Unit) = if (lev > 1) b def doError(b: => Unit) = if (lev > 0) b } @deprecated("this class is going to be removed in a future release", "2.7.7") class Debug(tag: String) extends Logger(tag) {}
すごい単純。デフォルトのログレベルが2(Warning以上)なので、普段は何も出力されないってわけですね。でも、warnとかを書いているコード、見たことないんですけど…。
スケープゴート的に、こんなコードを用意。
import scala.actors.{Actor, Debug} import scala.actors.Actor._ object DebugActor extends App { println("Create Debug Actor...") val debugActor = new DebugActor println("Debug Actor Start...") debugActor.start() println("Debug Actor Send Message...") debugActor ! "Hello World" println("Debug Actor Shutdown...") debugActor ! 'Shutdown } class DebugActor extends Actor { def act(): Unit = loop { react { case message: String => println("Received String Message[%s]".format(message)) case 'Shutdown => exit('normal) case message => println("Received Unknown Message[%s]".format(message)) } } }
いたって簡単なActorです。では、実行。
$ fsc DebugActor.scala $ scala DebugActor Create Debug Actor... Debug Actor Start... Debug Actor Send Message... Debug Actor Shutdown... Received String Message[Hello World]
では、最初を少しだけ変更。
import scala.actors.{Actor, Debug} import scala.actors.Actor._ object DebugActor extends App { Debug.level = 3 println("Create Debug Actor...") val debugActor = new DebugActor …省略…
これで実行してみましょう。
$ fsc DebugActor.scala $ scala DebugActor Create Debug Actor... Debug Actor Start... Info: initializing scala.actors.Scheduler$@1d2940b3... Info: scala.actors.scheduler.ThreadPoolConfig$@49ff0dde: java.version = 1.6.0_24 Info: scala.actors.scheduler.ThreadPoolConfig$@49ff0dde: java.vm.vendor = Sun Microsystems Inc. Info: scala.actors.scheduler.ForkJoinScheduler@303020ad: parallelism 4 Info: scala.actors.scheduler.ForkJoinScheduler@303020ad: max pool size 256 Info: scala.actors.Scheduler$@1d2940b3: starting new scala.actors.scheduler.ForkJoinScheduler@303020ad [class scala.actors.scheduler.ForkJoinScheduler] Debug Actor Send Message... Debug Actor Shutdown... Received String Message[Hello World] Info: scala.actors.scheduler.ForkJoinScheduler@303020ad: all actors terminated Info: scala.actors.scheduler.ForkJoinScheduler@303020ad: initiating shutdown...
なんか、盛大に出力が増えましたね。並列度、Schedulerの実装やSchedulerに属するActorが全て終了したことなどのメッセージが出力されるようになるようです。
知っていると便利…なのか?
あと、余談ですがActorで利用しているスレッドはデーモンスレッドではないようなので、Schedulerに属する全てのActorを終了しないとJavaVMが終了できないようですね。事実、上記コードからShutdownを投げている箇所を削除すると、ず〜っと終了を待ち続けるようになってしまいます。DaemonActor使えって?