Akka.NET有效地查询演员

时间:2016-01-30 18:19:16

标签: task-parallel-library akka.net

我正在使用Akka.NET为生产项目创建一个概念验证,但我正面临一个查询概念理解问题。

情况如下: CoordinatorActor有一个包含数千个Hotel-Actors的列表。

我想查询所有Hotel-Actors所有可在特定日期有空房的酒店。

当然,我可以通过他们预约并发送.Ask<>特定日期的请求。持有所有任务的参考并执行Task.WhenAll(requests)。但这感觉有点不自然。

或者我可以一次向所有酒店发送带有特定日期请求的广播消息(ActorSelection或路由器),但后来我不知道他们所有何时回复{ {1}}消息。

有没有人有建议如何解决这个问题?

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