0

是否可以向我们期望匹配多个参与者的通配符选择发送消息,并对所有响应执行某些操作?

我的第一个想法是这样的:

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

但这不起作用,因为 ask 不会返回通过将消息发送给所有参与者创建的所有期货的 Iterable,只是在任何参与者回复时返回的单个期货。

4

2 回答 2

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])
}

这里的一般想法是使用另一个短暂的临时演员作为处理聚合来自选择的响应的中间人。在响应发件人之前,它必须等待提供的请求超时的全部时间,因为正如我所提到的,它不知道要等待多少响应。你可以像这样使用它:

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 回答
2

如果您想获得对 actor 邮箱的所有响应self,您可以使用!带有显式sender参数的方法,如下所示:

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

In Actor selfis implicitso 编译器会sender隐式使用它。您可以发送消息:

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

如果你想对所有响应做一些特别的事情,你可以创建额外的演员并sender!方法中指定它,但你必须手动停止这个额外的演员。

于 2013-09-09T12:49:11.363 回答