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!、2回目の呼び出しで例外が発生します。ここでは間違ったパターンを使用していると思います。誰かがこれを達成する方法を助けることができますか?私は欲しい

  • オンデマンドでアクターを作成する
  • IDでアクターを検索し、存在しない場合は作成します
  • もう一度必要かどうかわからないので、破壊する能力

これにはディスパッチャーまたはルーターを使用する必要がありますか?

解決策 提案されているように、マップで使用可能なアクターを保持する具体的なスーパーバイザーを使用します。彼の子供のうちの1人を提供するように頼むことができます。

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 を使用していませんが、アクターの作成者はデフォルトでスーパーバイザーです。したがって、親は終了を聞くことができます。

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 }

それは解決策ですか?「terminated is always true => Actor name 1 is not unique!」の意味が完全には理解できなかったと言わざるを得ません。

于 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 に答える