当前位置: 首页 > 知识库问答 >
问题:

按需演员获取或创建

华安民
2023-03-14

我可以使用actorOf创建演员,并使用actorFor查看他们。现在我想通过一些id:String获得一个actor,如果它不存在,我想创建它。大概是这样的:

  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总是正确的,而且我得到演员名1不是唯一的 第二次调用的异常。我想我在这里用错了图案。有人能帮助实现这一点吗?我需要

  • 按需创建演员
  • 通过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]
  }
  ...
}

共有3个答案

昌乐生
2023-03-14

我基于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继承并实现responsibleereceive。注意:此代码尚未经过彻底测试,可能仍存在一些问题。我使用了一些错误处理来提高可读性。

司英彦
2023-03-14

角色只能由其父级创建,从您的描述中,我假设您正试图让系统创建一个非顶级角色,这将永远失败。你应该做的是给父母发送一条信息,说“把那个孩子给我”,然后父母可以检查它是否当前存在,健康状况良好等。,可能会创建一个新的,然后用适当的结果消息来回应。

重申这一极其重要的一点:get或create只能由直接家长完成。

萧献
2023-03-14

我使用akka的时间不长,但默认情况下,演员的创建者是他们的主管。因此,父母可以倾听他们的终止;

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 }

这是解决办法吗?我必须说我不完全理解你所说的“终止总是真的=

 类似资料:
  • 问题内容: 我正在尝试使用ActorFor获取现有的ActorRef,或者如果不存在则创建一个新的。我有以下代码,但它似乎没有按预期工作。.isTerminated()始终为true。 我在这里想念什么?提前致谢。 问题答案: “获取或创建”只能由指定的actor 的 父级 执行,因为只有该父级可以创建actor(如果不存在),并且只有父级才能一致地创建(即没有竞争条件)。在演员中,您可以做 不要

  • 我正在尝试使用ActorFor获取现有的ActorRef,或者如果它不存在,则创建一个新的ActorRef。我有以下代码,但它似乎没有按预期工作。isTerminated()总是正确的。 我错过了什么?提前谢谢。

  • 让我们假设一个使用Akka Typed实现的应用程序有一个持久执行元。这个持久执行元作为其操作的一部分创建了瞬态(或非持久)子执行元,每个子执行元都有一个唯一的ID,这些ID是持久状态的一部分。持久执行元还需要一些与其子级通信的方式,但我们不希望持久化子级的,因为它们实际上不是状态的一部分。在恢复时,持久参与者应该基于恢复的状态重新创建它的子级。这听起来并不像是一个很不寻常的用例,我正在试图弄清楚

  • 我可以在不同的变体中看到类似的问题,但还没有找到一个明确的答案。 null 这两个函数都应该是幂等的,因为使用轮询机制下载的文件不应该在临时拉取中再次下载,反之亦然。这两种访问方式都应该下载所有尚未下载的可用文件(可能会有不止一个新文件--我在这里看到了一个类似的问题,用于按需获取,但它是针对单个文件的)。 我想避免通过pollEnrich来修改SFTP-我的理解是,每个pollEnrich都将从

  • 我对阿克卡很陌生,我有一个(希望)简单的问题。我有一个参与者需要重复执行某个小的子任务——也就是说,每次这个参与者收到消息时,它都必须执行N个子任务。这个子任务是我指定给儿童演员的。我的问题是,我是否应该为每个子任务创建一个新的子角色实例?或者我应该简单地产生一个孩子演员,并发送N条消息?在这种情况下,最好的做法是什么? 为了更好地说明我的问题,这里有两个简化的示例(在Java中-但希望对Scal