+ -

Programming in Scala ch30 (Actor..

时间:2010-09-27

来源:jamesqiu

在手机上看
手机扫描阅读

 

30.3        原生线程和actor(P612)

actor管理1个或多个原生线程,但使用actor时不用考虑它和原生线程的对应关系。

每个原生线程也被作为一个actor来使用,但不能通过Thread.current来直接获取当前actor的线程,需要使用Actor.self,这在Scala的交互式REPL环境中调试actos时很有用:

scala> import scala.actors.Actor._

scala> self ! "hello"

scala>  self.receive { case x => x }

res9: Any = hello

没有消息的情况下调用self.receive { case x=>x }会一直阻塞,但receiveWith超时可退出:

scala>  self.receiveWithin(1000) { case x => x } // 等1秒

res0: Any = TIMEOUT

 

30.4        线程复用以提高性能(P613)

actor在Java线程之上包装实现,实际上每个actor都有其对应的线程。

Java中的线程并没有想象中的轻量,线程需要更多内存,一般可容纳百万级数量objects的JVM仅能容纳上千级别数量的线程。更糟糕的是,线程间的切换常常需要几百乃至上千个CPU时钟周期。如果需要程序尽可能高效,很重要的一点就是要减少线程的创建和线程间的切换。

为了复用线程,Scala提供了receive方法之外的另一选择:react。react和receive用法差不多,不过react处理消息后并无返回值,react处理消息的结果是Nothing类型(其实react处理完消息后是抛异常)。

由于react方法不需要返回,其实现就无需保存当前线程的调用栈,所以当前线程可以被下一个唤醒的actor所使用。该方法很高效,如果程序中所有actor都使用react方法而不是receive方法,只需一个线程就可以处理程序所有的actor(如果计算机是多核CPU,actor就会生成足够多的线程以充分利用CPU所有的核)。

    提示:尽可能地使用react来复用线程。

    由于react不返回,它处理完消息后还需要进行后续处理。一种常用方法是处理完消息后调用react的上层方法act自身,如:

  import actors._, actors.Actor._, java.net._

  object NameResolver extends Actor { // 得到域名对应的ip

    def act() {

      react {

        case (name: String, actor: Actor) => actor ! getIp(name); act()

        case "EXIT" => println("Name resolver exiting.")

        case msg => println("Unhandled message: " + msg); act()

      }

    }

    def getIp(name: String): Option[InetAddress] = {

      try { Some(InetAddress.getByName(name))

      } catch { case _: UnknownHostException => None }

    }

  }

// 调用:

scala> NameResolver.start()

scala> NameResolver ! ("www.scala-lang.org", self)

scala> self.receiveWithin(0) { case x => x }

res3: Any = Some(www.scala-lang.org/128.178.154.159)

scala> NameResolver ! ("wwwwww.scala-lang.org", self)

scala> self.receiveWithin(0) { case x => x }        

res5: Any = None

 

    这种方法很常用,故actors.Actor中已经提供了loop函数来完成这个工作,loop循环执行之后程序块{..}的代码。上面的NameResolver可以改写如下:

  def act() {

    loop {

      react {

        case (name: String, actor: Actor) => actor ! getIp(name)

        case msg => println("Unhandled message: " + msg)

      }

    }

  }

 

热门下载

更多