异步发送一个消息并立即返回。
target.tell(message, getSelf());
在Actor外部,如果没有回复,第二个参数可以为null;
异步发送一条消息并返回一个 Future代表一个可能的回应
target.forward(result, getContext());
使用ask会造成性能影响,因为当超时是,一些事情需要保持追踪。这需要一些东西来将一个Promise连接进入ActorRef,并且需要通过远程连接可到达的。所以总是使用tell更偏向性能,除非必须才用ask。
如果在角色外部需要一个回复,你可以使用ASK模式描
ask 模式既包含actor也包含future, 所以它是作为一种使用模式,而不是ActorRef的方法:
ask和future上的pipe模式一起使用是一个常用的组合,
final Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
final ArrayListObject>> futures = new ArrayListObject>>();
futures.add(ask(actorA, "request", 1000));
futures.add(ask(actorB, "another request", t));
final FutureObject>> aggregate = Futures.sequence(futures,
system.dispatcher());
final Future transformed = aggregate.map(
new MapperObject>, Result>() {
public Result apply(Iterable<Object> coll) {
final Iterator<Object> it = coll.iterator();
final String x = (String) it.next();
final String s = (String) it.next();
return new Result(x, s);
}
}, system.dispatcher());
pipe(transformed, system.dispatcher()).to(actorC);
ask 产生 Future, 两个通过Futures.sequence和map方法组合成一个新的Future,然后用 pipe 在future上安装一个 onComplete-处理器来完成将收集到的 Result 发送到其它actor的动作。使用 ask 将会像tell 一样发送消息给接收方, 接收方必须通过getSender().tell(reply, getSelf()) 发送回应来为返回的 Future 填充数据。ask 操作包括创建一个内部actor来处理回应,必须为这个内部actor指定一个超时期限,过了超时期限内部actor将被销毁以防止内存泄露。
如果一个actor 没有完成future , 它会在超时时限到来时过期, 明确作为一个参数传给ask方法,以 AskTimeoutException来完成Future。
try {
String result = operation();
getSender().tell(result, getSelf());
} catch (Exception e) {
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
throw e;
}
Future的onComplete, onResult, 或 onTimeout 方法可以用来注册一个回调,以便在Future完成时得到通知。从而提供一种避免阻塞的方法。
使用future回调时,在角色内部要避免使用关闭该角色的引用(不要在回调中调用该角色的方法或访问其可变状态)这会破坏角色的封装,会引用同步bug和race condition, 因为回调会与此角色一同被并发调度。 目前还没有一种编译时的方法能够探测到这种非法访问。