首页 > 解决方案 > Proto.Actor 中的异步请求/响应?

问题描述

我是 proto.actor/actor 编程的新手,我想知道这是否可以实现这种行为:

演员 A 通过异步命令询问演员 B——他应该等待响应以实现请求/响应模型,但使用任务。演员 B 正在使用 HTTP 请求,所以这将是一些异步 IO 操作,所以我不希望它在这段时间内被其他演员阻止,所以当 10 个演员同时询问他时,每个请求都会排队,但首先请求正在等待进程,第二个应该有机会继续。一旦第一个请求完成,它应该在队列中具有优先级并获得对参与者 A 的响应。

如何获得这个流量?

例如,我有 3 个客户端向服务请求一些数据,服务调用需要 5 秒,而大部分时间服务花费在 IO 上。在当前的实现中,我们总共有 15 秒的时间来处理所有请求,但我希望它需要大约 5-6 秒

 public static class ProtoTest
    {
        public static PID Service;

        public static async Task Start()
        {
            var context = new RootContext();

            var props = Props.FromProducer(() => new ClientActor());
            var serviceProps = Props.FromProducer(() => new ServiceActor());
            Service = context.Spawn(serviceProps);

            var jobs = new List<Task>();
            for (int i = 0; i < 3; i++)
            {
                string actorName = $"Actor_{i}";
                jobs.Add(Task.Run(() =>
                {
                    var client = context.SpawnNamed(props, actorName);
                    context.Send(client, new Command());
                }));
            }

            Console.ReadLine();
        }
    }

    public class ClientActor : IActor
    {
        public virtual async Task ReceiveAsync(IContext context)
        {
            if (context.Message is Command)
            {
                Console.WriteLine($"{DateTime.Now.ToLongTimeString()} START processing by {context.Self.Id}");
                var result = await context.RequestAsync<string>(ProtoTest.Service, new Query());
                Console.WriteLine($"{DateTime.Now.ToLongTimeString()} End processing by {context.Self.Id}");
            }

            return;
        }
    }

    public class ServiceActor : IActor
    {
        public async virtual Task ReceiveAsync(IContext context)
        {
            if (context.Message is Query)
            {
                // this operation is taking long time so actor could handle others in this time
                await Task.Delay(5000);

                context.Respond("result");
            }

            return;
        }
    }

标签: protractoractorproto.actor

解决方案


Actor 的核心原则之一是它不会并行执行多个操作。如果我正确理解您的问题,您可以做的是为您想要并行运行的每个操作创建一个新的参与者(参与者很便宜,所以创建很多不是问题)。因此,如果参与者 A 需要发送 N 个要异步处理的命令并在收到每个结果时接收它们,它可以生成 N 个参与者 B1、B2...Bn(每个命令一个)并向每个参与者发送一个请求。B 演员等待结果,然后回复 A 演员。然后,每个响应将作为消息发送到参与者 A 的邮箱,并按照它们完成的顺序依次处理。


推荐阅读