1

我有一个有很多孩子的演员,我正在查询它以获取其孩子中的数据聚合。此操作可能需要几秒钟。

我正要这样做,感觉完全错了。句柄方法由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()));
}

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

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

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

4

1 回答 1

5

一般来说Ask,应该只用于与来自外部服务的参与者的通信,几乎从不用于两个参与者之间。它比使用Tell. 另一个问题是使用Task.WaitAllwhich 实际上阻塞当前线程,直到所有响应都到达,这对性能也很不利,并且可能最终导致死锁。

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

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

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

PS:不要使用 TypedActor - 它对性能也很不利,并且已经/将过时。

于 2015-09-07T07:28:12.127 回答