0

複数のアクターに一致すると予想されるワイルドカードを使用したアクターの選択にメッセージを送信し、すべての応答に対して何かを行うことは可能ですか?

私の最初の考えは次のようなものでした:

sequence(context.actorSelection("/actors*") ? Message).onSuccess {
    println("The results are " + _)
}

しかし、ask は、すべてのアクターにメッセージを送信することによって作成されたすべてのフューチャーに対して Iterable を返さず、いずれかのアクターが応答したときに返される単一のフューチャーのみを返すため、これは機能しません。

4

2 に答える 2

2

アクターのメールボックスへのすべての応答を取得したい場合は、次のようにメソッドを明示的な引数とともにself使用できます。!sender

context.actorSelection("/actors*").!(Message)(self)

これActor selfimplicit、コンパイラがsender暗黙的に使用するためです。メッセージを送信するだけです:

context.actorSelection("/actors*") ! Message

すべての応答で何か特別なことをしたい場合は、追加のアクターを作成しsender!メソッドで指定することができますが、この追加のアクターを手動で停止する必要があります。

于 2013-09-09T12:49:11.363 に答える
2

ここでの問題は、senia が指摘したように、不明な数のアクターに応答を求めることになるため、いつ応答を待っているかを知るのが非常に難しくなることです。応答を受け取る前に常にヒットする待機のタイムアウトを指定するのがクールな場合は、次のようなことができると思います。

//Message to send to the temp actor that handles request/response to the selection
case class AskSelection(path:String, msg:Any, askTimeout:FiniteDuration)

//Actor that handles the request to aggregate responses from a selection
class SelectionAsker extends Actor{
  import context._      
  var responses:List[Any] = List.empty      

  def receive = waitingForRequest

  def waitingForRequest:Receive = {
    case request @ AskSelection(path, msg, askTO) =>                
      system.actorSelection(path) ! msg          
      setReceiveTimeout(askTO)
      become(waitingForResponses(sender, askTO.fromNow))
  }

  def waitingForResponses(originator:ActorRef, deadline:Deadline):Receive = {
    case ReceiveTimeout => 
      originator ! responses
      context.stop(self)          
    case any =>           
      responses = any :: responses
      setReceiveTimeout(deadline.timeLeft)
  }
}

//Factory to create the selection asker
object SelectionAsker{
  def apply(fact:ActorRefFactory) = fact.actorOf(Props[SelectionAsker])
}

ここでの一般的な考え方は、別の短命で一時的なアクターを仲介役として使用して、選択からの応答を集約するというものです。前述のように、待機する応答の数がわからないため、送信者に応答する前に、指定された ask タイムアウトの全量を待機する必要があります。次のように使用できます。

val system = ActorSystem("test")
system.actorOf(Props[ActorA], "actor-a")
system.actorOf(Props[ActorB], "actor-b")
implicit val timeout = Timeout(2 seconds)
import system._

val asker = SelectionAsker(system)
(asker ? AskSelection("/user/actor*", "foo", 1 seconds)) onComplete { tr =>
  println(tr)
}

class ActorA extends Actor{
  def receive = {
    case _ => 
      sender ! "a"
  }
}

class ActorB extends Actor{
  def receive = {
    case _ => 
      sender ! "b"   
  }
}

きれいではありませんが、これが本当に必要な場合はうまくいく可能性があります。しかし、それが最初にやりたいことであり、ユースケースに追加する必要がある少し余分なコードであるため、最初により良い簡単なオプションがないことを確認する必要があります。

于 2013-09-09T16:39:42.073 に答える