我正在使用Akka.NET为生产项目创建一个概念验证,但我正面临一个查询概念理解问题。
情况如下:
CoordinatorActor有一个包含数千个Hotel-Actors
的列表。
我想查询所有Hotel-Actors
所有可在特定日期有空房的酒店。
当然,我可以通过他们预约并发送.Ask<>
特定日期的请求。持有所有任务的参考并执行Task.WhenAll(requests)
。但这感觉有点不自然。
或者我可以一次向所有酒店发送带有特定日期请求的广播消息(ActorSelection或路由器),但后来我不知道他们所有何时回复{ {1}}消息。
有没有人有建议如何解决这个问题?
答案 0 :(得分:3)
是的,你的感受就在这里。使用Ask进行actor之间的通信被认为是非常低效的 - 主要是因为每个ask需要分配单独的消息监听器。
第一个好问题是:你需要等待所有人回复吗?也许响应可以在它们到来时发出。
如果您需要在回复之前收集所有数据,您需要有一些方法来计算所有邮件,以保证其中一些邮件是否仍然未决 - 在这种情况下使用ActorSelection
是不可行。您需要与每条消息相关联的计数器或标识符列表 - 虽然它们甚至可以是普通数字,但通常IActorRef
更容易使用。
下面您可以看到可以为此特定任务创建的Aggregator
actor的简化示例 - 一旦没有其他消息需要等待,它将自动返回所有回复,收到并自行停止超时已经发生。
class Aggregator<T> : ReceiveActor
{
private IActorRef originalSender;
private ISet<IActorRef> refs;
public Aggregator(ISet<IActorRef> refs)
{
this.refs = refs;
// this operation will finish after 30 sec of inactivity
// (when no new message arrived)
Context.SetReceiveTimeout(TimeSpan.FromSeconds(30));
ReceiveAny(x =>
{
originalSender = Sender;
foreach (var aref in refs) aref.Tell(x);
Become(Aggregating);
});
}
private void Aggregating()
{
var replies = new List<T>();
// when timeout occurred, we reply with what we've got so far
Receive<ReceiveTimeout>(_ => ReplyAndStop(replies));
Receive<T>(x =>
{
if (refs.Remove(Sender)) replies.Add(x);
if (refs.Count == 0) ReplyAndStop(replies);
});
}
private void ReplyAndStop(List<T> replies)
{
originalSender.Tell(new AggregatedReply<T>(replies));
Context.Stop(Self);
}
}