2015-09-06 56 views
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延续,但仍然不相信这是正确的阿卡方式 - 这是重点。我可以让它工作,我只想知道最佳实践方案。

回答

5

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

类似thread已经在github上讨论过。

的聚集问题,一般的解决方法是:

  • 创建聚集过程一个单独的演员。
  • 使用演员列表进行初始化,它应该从演员收集数据并记住演员,演员将收到结果通知。
  • 发送请求/查询每个演员。
  • 处理每个请求/查询响应,在单独的数据结构聚集并从等待行动者的列表中删除发送者。
  • 一旦没有演员等待 - 发送结果并停止当前演员(负责数据聚合的演员)。
  • 连接的情况下,ReceiveTimeout机制,当由于某种原因,不是所有的演员都能够合理的时间内作出反应 - 当超时会打,你可能会返回故障或迄今收集的响应列表。

PS:不要使用TypedActor - 它对性能也不好,并且/将会过时。

+1

很感谢。问题让我感到惊讶。所以你说的要求比一个告诉给发件人的响应要告诉更贵?是啊,WaitAll是让我流眼泪的原因。伟大的联系,认为这不是我想要的,然后成为一块真棒。 –

+3

Ask价格昂贵的原因是它既创建了一个任务,也是一个临时演员,将会收到来自被问到的演员的回应。临时演员也注册在'/ temp'下,注册和取消注册也有些贵。 –

+0

很好,非常感谢,非常有趣:D –