Akka.NET query actors efficiently

时光怂恿深爱的人放手 提交于 2019-12-11 12:47:17

问题


I'm creating a proof of concept with Akka.NET for a production project but I'm facing a query concept understanding problem.

Situation is a follows: CoordinatorActor has a list of thousands of Hotel-Actors.

I would like to query all Hotel-Actors for all hotels with a room available on a specific date.

Of course I could foreach through them and sent a .Ask<> request for the specific date. Holding a reference of all the tasks and do a Task.WhenAll(requests). But that feels a little unnatural.

Alternatively I could send a broadcast message with a request for the specific date to all hotels at once (ActorSelection or router), but then I don't know when they all responded back with a Tell message.

Does anyone has a suggestion how to solve this?


回答1:


Yes, your feelings are right here. Using Ask for communication between actors is considered highly inefficient - mostly because of each ask needs to allocate separate message listener.

First good question would be: do you need to wait for them all to respond back? Maybe responses can be emitted as they come.

In case, when you need to collect all of the data before replying, you need to have some way of counting all messages in order to guarantee if some of them are still pending - in that case using ActorSelection is not feasible. You'll need counter or list of identifiers that could be associated with each message - while they can be even ordinary numbers, usually IActorRefs are easier to work with.

Below you can see simplified example of Aggregator actor that can be created for this particular task - it will automatically return all replies, it received, and stop itself, once there are no more messages to wait for or a timeout has occurred.

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


来源:https://stackoverflow.com/questions/35105339/akka-net-query-actors-efficiently

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!