Akka中ask和tell的区别是什么?

15

阅读Scala文档时,我很难理解ask和tell之间的区别。

http://doc.akka.io/docs/akka/snapshot/scala/actors.html中写道:

! 表示“fire-and-forget”,例如异步发送消息并立即返回。也称为 tell。

? 异步发送消息并返回表示可能回复的Future。也称为 ask。

如果我使用的Actor生成了一个Web请求,那么ask和tell之间有什么区别?在两种情况下,请求将被异步生成并必须等待响应,换句话说,如果Actor调用Web服务并等待响应,那么“tell”如何立即返回?

2个回答

16

asktell 的区别在于消息发送者的角度(不一定是一个角色)。使用 ask 会发送消息并返回一个 future 对象,可以等待直到超时或收到答复;而使用 tell 则会立即发送消息并返回。

对于 ask,接收到消息的角色应该在操作完成后回复发送者。


如果tell立即从需要30秒才能返回的进程中返回,那么它返回什么?或者说,tell用于不期望返回值的情况,而ask用于期望在某个时间点返回值的情况下使用吗? - blue-sky
2
是的,没错。两者都会立即返回 -- tell 返回 Unit,也就是什么都没有,因此不需要返回值。ask 返回一个 Future[Any],可以被 await,或者被传递给另一个 actor,或者被 map 到一个回调函数中执行。ask 更加复杂,并且通过隐式转换为 akka.pattern.AskableActorRef 实现。 - Richard Close

12

看起来您已经了解了asktell之间的基本区别,但不清楚如何使用tell来涉及其他参与处理HTTP请求的对象。

为了在处理HTTP请求的处理程序中使用tell使其有意义,您必须使用一个不要求请求处理程序返回其响应的HTTP服务器。Spray就是这样的HTTP服务器。

在Spray中,请求处理程序不会返回其响应;它会得到一个RequestContext对象,并且响应请求需要调用它上面的某个方法。您可以将该RequestContext简单地发送给另一个参与者,然后该参与者就可以对请求做出响应:

path("foo") {
  rc => rc complete "foo"  // respond here
} ~
path("bar") {
  rc => barActor ! DoBar(rc)  // send it to bar; NO RESPONSE HERE
}

接着由barActor指代的演员可以说:

case DoBar(rc) =>
  rc complete "bar"  // respond here, in another actor

Spray将请求环境打包成一个对象,并可以从任何一个actor中传递和完成,这非常适用于actor模型。相反,如果您的Web框架要求调用的处理程序返回响应,那么如果想涉及另一个actor,您唯一的选择是使用ask
Typesafe宣布Play即将在其下使用Spray。我希望这意味着Play将允许将请求发送到其他actor进行处理。

据我了解,Tomcat也可以异步处理请求,而且所有现代Web服务器都可以异步处理请求。如果它们不能异步处理请求,那么请求很容易排队,导致服务器响应时间变慢。 - blue-sky
如果你的意思是它们允许你"异步地相互处理请求",那当然可以——很多都能做到。我在这里指的是HTTP服务器是否将处理程序调用为必须返回响应结果的方法。在这种情况下,单独的actor无法处理响应;处理程序必须使用ask来调用actor,并得到一个结果的Future。当结果到达时,原始的处理程序会重新运行以处理响应。 - AmigoNico
您能详细说明(或添加链接)使用“tell”设计系统的方式吗?似乎在“tell”设计中,如果请求是某个http请求,则第二个参与者应该知道响应的结构。换句话说,它看起来像是将Web接口委托到应用程序中,而不是将它们分开。另一个问题是,如果我需要组合两个响应,则我需要使用“ask”,或者我需要第一个被调用的参与者知道如何“告诉”第二个参与者。谢谢。 - ozma
目前找到了这个链接:http://bartoszsypytkowski.com/dont-ask-tell-2/。虽然是.NET相关的,但这个思路对于所有实现都是相关的。 - ozma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接