Scala,检查Actor是否已退出

时间:2010-11-28 15:53:45

标签: scala scala-2.8 exit actor worker-thread

在Scala 2.8中,当我开始演员时,我可以通过消息传递进行通信。这反过来意味着我可以发送最终的Exit()消息或我认为符合我的协议的任何内容。

但我如何检查演员是否退出?我可以很容易地想象自己有一个任务,主人演员开始一些工人演员,然后只是等待答案,每次检查这是否是最终答案(即任何演员是否仍在工作或他们都退出?)。

当然,我可以让他们都发回“我已经完成”的消息,然后计算它们,但这实际上并不令人满意。

测试完成工作人员时的最佳做法是什么?

修改#1

嘿伙计们,我正在调查期货,但遇到了麻烦。有人可以解释为什么这段代码不起作用:

package test
import scala.actors.Futures._

object FibFut extends Application{

    def fib(i:Int):Int = 
        if(i<2)
            1
        else
            fib(i-1)+fib(i-2)

    val f = future{ fib(3) }

    println(f())    

}

如果我在future-body中定义函数fib,它就有效。它必须是范围的东西,但我没有上面的任何错误,它只是挂起。任何人吗?

修改#2

似乎扩展应用程序并不是一个好方法。定义主要方法使一切正常。以下代码是我正在寻找的,所以期货竖起大拇指:)

package test

import scala.actors.Futures._

object FibFut {

  def fib(i: Int): Int = if (i < 2) 1 else fib(i - 1) + fib(i - 2)

  def main(args: Array[String]) {

    val fibs = for (i <- 0 to 50) yield future { fib(i) }

    for (future <- fibs) println(future())

  }

}

3 个答案:

答案 0 :(得分:3)

我个人喜欢“我已经完成”的粉丝;这是管理工作分配的好方法,作为奖励,你已经知道所有孩子什么时候完成了他们正在做的事情。

但是,如果您真的只想将某些工作一次并等待一切准备就绪,请查看scala.actors.Futures。你可以要求它做一些计算:

val futureA = Futures.future {
  val a = veryExpensiveOperation
  (a,"I'm from the future!")
}

如果您提出了多个请求,那么您可以等待所有事情完成:

Futures.awaitAll(600*1000, futureA, futureB, futureC, futureD)
// Returns once all of A-D have been computed
val actualA = futureA()   // Now we get the value

答案 1 :(得分:2)

前段时间我在Scala中链接actor时写了a post。 Actor链接是在Erlang,Scala Actors和其他actor库中监视actor的惯用[和最简单]方法。通过defalt,当你链接2个actor时,其中一个死亡,另一个立即死亡(除非演员陷阱/处理退出信号):

scala> case object Stop
defined module Stop

scala>

scala> val actor1 = actor {
     |    loop {
     |       react {
     |          case Stop =>
     |             println("Actor 1: stop")
     |             exit()
     |          case msg => println(msg)
     |             }
     |         }
     | }
actor1: scala.actors.Actor = scala.actors.Actor$$anon$1@1feea62

scala>

scala> val actor2 = actor {
     |    link(actor1)
     |    self.trapExit = true
     |    loop {
     |       react {
     |          case msg => println(msg)
     |             }
     |         }
     | }
actor2: scala.actors.Actor = scala.actors.Actor$$anon$1@1e1c66a

scala> actor1.start
res12: scala.actors.Actor = scala.actors.Actor$$anon$1@1feea62

scala> actor2.start
res13: scala.actors.Actor = scala.actors.Actor$$anon$1@1e1c66a

scala> actor1 ! Stop
Actor 1: stop

scala> Exit(scala.actors.Actor$$anon$1@1feea62,'normal)  // Actor 2 received message, when Actor1 died

更复杂和灵活的方式是使用主管(Erlang中的主管行为,Akka Actors库中的 actor supervisors 等)。一个主管(本身就是一个演员)监视其他一些演员,并根据指定的策略重新启动它们(重新启动所有演员,如果一个演员死亡;重新启动只有一个演员,当它死亡时)。

答案 2 :(得分:0)

好的,大家,我已经提出了使用actor类的getState函数的解决方案。在解决方案中,我使用了这个主题的想法:Best method to peek into a Scala Actor's Mailbox 其中使用reactWithin(0)。我在使用react和loop时遇到了麻烦,程序只会阻止重大计算。这是通过将while(true)和reactWithin(int)替换为receiveWithin(int)来解决的。

我的解决方案如下(请注意,bigass代码块):

package test

import scala.actors._
import scala.actors.Actor.State._

case class Computation(index: Int, a: () ⇒ Int)
case class Result(i: String)
object Main {
  def main(args: Array[String]) {
    val m = new Master
    m.start
  }
}

class Master extends Actor {

  val N = 40
  var numberOfAnswers = 0

  def fib(x: Int): Int =
    if (x < 2)
      1
    else
      fib(x - 1) + fib(x - 2)

  val computers = for (i ← 0 to N) yield new Computer

  def act {

    for (i ← 0 until computers.size) {
      computers(i).start
      computers(i) ! Computation(i, () => fib(i))
    }

    println("done Initializing actors")
    while (true) {
      receiveWithin(1000) {

        case Result(i) =>
          val numberDone = computers.map(_.getState == Terminated).filter(_ == true).length
          println(i)
          numberOfAnswers += 1

        case TIMEOUT =>
          val allDone = computers.map(_.getState == Terminated).reduceRight(_ && _)
          println("All workers done?:" + allDone)
          println("# of answers:" + numberOfAnswers)
          if (allDone)
            exit()
      }
    }

  }

}

class Computer extends Actor {

  def act {
    loop {
      react {
        case Computation(i, f) ⇒
          sender ! Result("#" + i + " Res:" + f())
          exit()
      }
    }
  }

}

该程序计算斐波那契数(以最坏的方式)。这个想法只是测试多个线程对大型工作负载的利用率。以下行检查某个actor是否尚未终止:

computers.map(_.getState == Terminated).reduceRight(_ && _)

其中计算机的类型为IndexedSeq [Computer]。诀窍是使用TIMEOUT消息,我可以定期检查所有工作是否完成并采取相应措施(在这种情况下,当没有更多活动工人时退出)。我利用每个工人在退出之前发送结果的事实。通过这种方式,我知道我将始终收到结果并处理它们,然后才会显示为已终止。

当我使用react和loop而不是while(true)并接收时,有人可以评论程序“锁定”(停止接收消息)的事实吗?