23

我可以用 来创建演员actorOf并用actorFor. 我现在想通过一些演员得到一个演员id:String,如果它不存在,我希望它被创造出来。像这样的东西:

  def getRCActor(id: String):ActorRef = {
    Logger.info("getting actor %s".format(id))
    var a = system.actorFor(id)
    if(a.isTerminated){
      Logger.info("actor is terminated, creating new one")
      return system.actorOf(Props[RC], id:String)
    }else{
      return a
    }
   }

但这并不像isTerminated往常一样actor name 1 is not unique!有效,第二次通话我得到了例外。我想我在这里使用了错误的模式。有人可以帮助如何实现这一目标吗?我需要

  • 按需创建演员
  • 按 id 查找演员,如果不存在则创建他们
  • 破坏能力,因为我不知道我是否会再次需要它

我应该为此使用调度程序还是路由器?

解决方案 正如建议的那样,我使用了一个具体的主管,它将可用的参与者保存在地图中。可以要求提供他的一个孩子。

class RCSupervisor extends Actor {

  implicit val timeout = Timeout(1 second)
  var as = Map.empty[String, ActorRef]

  def getRCActor(id: String) = as get id getOrElse {
    val c = context actorOf Props[RC]
    as += id -> c
    context watch c
    Logger.info("created actor")
    c
  }

  def receive = {

    case Find(id) => {
      sender ! getRCActor(id)
    }

    case Terminated(ref) => {
      Logger.info("actor terminated")
      as = as filterNot { case (_, v) => v == ref }
    }
  }
}

他的同伴对象

object RCSupervisor {

  // this is specific to Playframework (Play's default actor system)
  var supervisor = Akka.system.actorOf(Props[RCSupervisor])

  implicit val timeout = Timeout(1 second)

  def findA(id: String): ActorRef = {
    val f = (supervisor ? Find(id))
    Await.result(f, timeout.duration).asInstanceOf[ActorRef]
  }
  ...
}
4

4 回答 4

14

我已经很久没有使用akka了,但是actors的创建者默认是他们的supervisor。因此,父母可以听取他们的终止;

var as = Map.empty[String, ActorRef] 
def getRCActor(id: String) = as get id getOrElse {
  val c = context actorOf Props[RC]
  as += id -> c
  context watch c
  c
}

但显然你需要注意他们的终止;

def receive = {
  case Terminated(ref) => as = as filterNot { case (_, v) => v == ref }

这是一个解决方案吗?我必须说我没有完全理解“终止总是正确的 => 演员姓名 1 不是唯一的!”的意​​思。

于 2012-05-26T16:16:36.940 回答
13

演员只能由他们的父母创建,根据您的描述,我假设您正试图让系统创建一个非顶级演员,这总是会失败。你应该做的是向父母发送一条消息说“把那个孩子给我”,然后父母可以检查它当前是否存在,是否健康等,可能创建一个新的,然后以适当的方式回复结果消息。

重申这一点非常重要:get-or-create 只能由直接父级完成。

于 2012-05-27T07:03:26.413 回答
2

我基于 oxbow_lakes 的代码/建议来解决这个问题,但我没有创建所有子角色的简单集合,而是使用(双向)地图,如果子角色的数量很大,这可能是有益的。

import play.api._
import akka.actor._
import scala.collection.mutable.Map 

trait ResponsibleActor[K] extends Actor {
  val keyActorRefMap: Map[K, ActorRef] = Map[K, ActorRef]()
  val actorRefKeyMap: Map[ActorRef, K] = Map[ActorRef, K]()

  def getOrCreateActor(key: K, props: => Props, name: => String): ActorRef = {
    keyActorRefMap get key match {
      case Some(ar) => ar
      case None =>  {
        val newRef: ActorRef = context.actorOf(props, name)
        //newRef shouldn't be present in the map already (if the key is different)
        actorRefKeyMap get newRef match{
          case Some(x) => throw new Exception{}
          case None =>
        }
        keyActorRefMap += Tuple2(key, newRef)
        actorRefKeyMap += Tuple2(newRef, key)
        newRef
      }
    }
  }

  def getOrCreateActorSimple(key: K, props: => Props): ActorRef = getOrCreateActor(key, props, key.toString)

  /**
   * method analogous to Actor's receive. Any subclasses should implement this method to handle all messages
   * except for the Terminate(ref) message passed from children
   */
  def responsibleReceive: Receive

  def receive: Receive = {
    case Terminated(ref) => {
      //removing both key and actor ref from both maps
      val pr: Option[Tuple2[K, ActorRef]] = for{
        key <- actorRefKeyMap.get(ref)
        reref <- keyActorRefMap.get(key)
      } yield (key, reref)

      pr match {
        case None => //error
        case Some((key, reref)) => {
          actorRefKeyMap -= ref
          keyActorRefMap -= key
        }
      }
    }
    case sth => responsibleReceive(sth)
  }
}

要使用此功能,您继承ResponsibleActor并实现responsibleReceive. 注意:此代码尚未经过彻底测试,可能仍有一些问题。我省略了一些错误处理以提高可读性。

于 2012-12-09T19:49:05.760 回答
0

目前,您可以在 Akka 中使用 Guice 依赖注入,这在http://www.lightbend.com/activator/template/activator-akka-scala-guice中有说明。您必须为演员创建一个随附的模块。然后,在其配置方法中,您需要创建一个与参与者类和一些属性的命名绑定。属性可能来自配置,例如,为参与者配置了路由器。您还可以通过编程方式将路由器配置放在那里。任何你需要使用@Named("actorname") 来引用你注入的actor 的地方。配置的路由器将在需要时创建一个actor实例。

于 2017-03-15T16:01:38.413 回答