嵌套分叉的正确模式

Joh*_*las 1 c# akka.net

我有一个有许多孩子的演员,我正在查询它以获得其子女的数据汇总.此操作可能需要几秒钟.

我即将这样做,感觉非常错误.handle方法由a调用Ask<>.

public void Handle(Message message)
{
    var children = Context.GetChildren();
    var tasks = new List<Task<Result>>();

    foreach (var child in children)
    {
        var t = child.Ask<Result>(new Query);
        tasks.Add(t);
    }

    Task.WaitAll(tasks.ToArray()); // Gah!
    // do some work
    Sender.Tell(new Response(new Results()));
}
Run Code Online (Sandbox Code Playgroud)

我有一些想法,但想得到一些意见,因为我真的不想重新发明一个20边的车轮.

Sender当我最终调用Tell它时,我担心引用和它将指向什么,因为它是一个静态调用.

我最终使用了Task.WhenAll延续,但仍然不相信它是正确的Akka方式 - 这就是重点.我可以使它工作,我只想知道最佳实践选项.

Bar*_*ski 5

一般来说,Ask应该只用于与外部服务的演员进行通信,几乎从不在两个演员之间.它比使用它贵很多Tell.另外一个问题是使用Task.WaitAll它实际阻止当前线程直到所有响应都到达,这对性能也有害并且可能最终导致死锁.

类似的线程已在github上讨论过了.

聚合问题的一般解决方案是:

  • 为聚合过程创建单独的actor.
  • 使用actor列表初始化它,它应该从actor中收集数据并记住actor,它将通过收集的结果通知.
  • 发送每个演员的请求/查询.
  • 处理每个请求/查询响应,将其聚合在单独的数据结构中,并从等待的actor列表中删除发送者.
  • 一旦没有参与者等待 - 发送结果并停止当前参与者(负责数据聚合的参与者).
  • 附加ReceiveTimeout机制以防万一,由于某些原因并非所有参与者都能够在合理的时间内做出响应 - 当超时时间到来时,您可能会返回到目前为止收集的失败或回复列表.

PS:不要使用TypedActor - 它对性能也有害,并且/将会被淘汰.

  • Ask很昂贵的原因是它创建了一个Task和一个临时actor,它将接收来自Asked actor的响应.临时演员也在`/ temp`下注册,注册和取消注册也有点贵. (3认同)