在Akka等待多个结果

在Akka等待多个结果,akka,actor,nonblocking,Akka,Actor,Nonblocking,在阿克卡等待多个参与者的结果的正确方式是什么 Coursera课程有一个复制键值存储的练习。在不深入了解任务细节的情况下,它需要等待多个参与者的确认,然后才能表明复制已完成 我使用一个包含未完成请求的可变映射来实现分配,但我觉得解决方案有一股“异味”。我希望有一个更好的方法来实现一个看似常见的场景 为了通过保留我对练习的解决方案来维护类的荣誉代码,我有一个描述类似问题的抽象用例 发票行项目需要计算其纳税义务。纳税义务是多个税务机关(如联邦、州、警区)对行项目适用的所有税收的组合。如果每个税务机关

在阿克卡等待多个参与者的结果的正确方式是什么

Coursera课程有一个复制键值存储的练习。在不深入了解任务细节的情况下,它需要等待多个参与者的确认,然后才能表明复制已完成

我使用一个包含未完成请求的可变映射来实现分配,但我觉得解决方案有一股“异味”。我希望有一个更好的方法来实现一个看似常见的场景

为了通过保留我对练习的解决方案来维护类的荣誉代码,我有一个描述类似问题的抽象用例


发票行项目需要计算其纳税义务。纳税义务是多个税务机关(如联邦、州、警区)对行项目适用的所有税收的组合。如果每个税务机关都是能够确定该行项目纳税义务的参与者,则该行项目将需要所有参与者进行报告,然后才能继续报告总体纳税义务。在Akka实现此场景的最佳/正确方法是什么?

这是Akka中非常常见的问题。你有多个演员为你做这项工作,你需要把他们结合起来

Jammie Allen在其著作《有效Akka》中提出的解决方案(关于从各种类型的账户中获取银行账户余额)是,你产生一个参与者,该参与者将产生多个参与者来完成这项工作(例如,计算你的税收)。它将等待所有人的回答

您不应该使用
询问
,而应该使用
告诉

当您向多个参与者(如FederalTaxactor、StateTasActor…)发送消息时,您会向他们发送一条消息,其中包含他们需要处理的数据。然后你知道你需要收集多少答案。对于每个响应,您检查是否所有响应都存在。如果不是,你就等着

问题是,如果任何演员失败,你可能会永远等待。因此,您可以为自己安排一条超时消息。如果不是所有答案都存在,则返回操作未成功完成


Akka有一个特殊的实用程序,可以为自己安排一个超时时间,这是一个很好的助手。

下面是一个简单的例子,我相信你正在寻找。它展示了一个像主人一样的演员是如何产生一些子工作人员,然后等待他们的所有响应,从而处理超时等待结果的情况。该解决方案展示了如何等待初始请求,然后在等待响应时切换到新的接收函数。它还显示了如何将状态传播到等待接收函数中,以避免在实例级别具有显式的可变状态

对象分类计算器{
封闭性状分类类型
案例对象StateTax扩展了TaxType
案例对象FederalTax扩展了TaxType
案例对象policyDistrictTax扩展TaxType
val AllTaxTypes:Set[TaxType]=Set(州税、联邦税、PolicyDistrictionTax)
案例类别GetTaxAmount(GrossSearnings:Double)
案例类TaxResult(taxType:taxType,amount:Double)
案例类别TotalTaxResult(taxAmount:Double)
案例对象TaxCalculationTimeout
}
类TaxCalculator扩展了Actor{
导入TaxCalculator_
导入上下文_
导入concurrent.duration_
def receive=等待请求
def waitingForRequest:接收={
案例gta:GetTaxAmount=>
val children=AllTaxTypes映射(tt=>actorOf(propsFor(tt)))
每个孩子(!gta)
setReceiveTimeout(2秒)
成为(等待响应(发件人,所有分类类型))
}
def waitingForResponses(respondTo:ActorRef,expectedTypes:Set[TaxType],tax:Map[TaxType,Double]=Map.empty):Receive={
案例税收结果(tt,金额)=>
val newTaxes=税收++映射(tt->金额)
if(newTaxes.keySet==预期类型){
响应!TotalTaxResult(newTaxes.values.foldLeft(0.0)(u+u2;))
上下文停止自我
}
否则{
成为(等待响应(响应、预期类型、新轴))
}
案例接收超时=>
响应!TaxCalculationTimeout
上下文停止自我
}
def propsFor(分类类型:分类类型)=分类类型匹配{
案例StateTax=>道具[StateTaxCalculator]
案例FederalTax=>Props[FederalTaxCalculator]
案例PoliceDistrictTax=>Props[PoliceDistrictTaxCalculator]
}  
}
trait TaxCalculatingActor扩展了Actor{
导入TaxCalculator_
val分类类型:分类类型
增值税百分比:双倍
def接收={
案例GetTaxAmount(收益)=>
增值税=收入*百分比
发件人!TaxResult(taxType,tax)
}
}
类FederatalTaxCalculator扩展了TaxCalculatingActor{
val taxType=TaxCalculator.FederalTax
val百分比=0.20
}
类StateTaxCalculator扩展了TaxCalculatingActor{
val taxType=TaxCalculator.StateTax
val百分比=0.10
}
类policyDistrictTaxCalculator扩展了TaxCalculatingActor{
val taxType=TaxCalculator.policyDistrictTax
val百分比=0.05
}
然后,您可以使用以下代码对此进行测试:

导入TaxCalculator_
导入akka.pattern.ask
导入concurrent.duration_
隐式val超时=超时(5秒)
val系统=ActorSystem(“税”)
导入系统_
val cal=system.actorOf(Props[TaxCalculator])
val fut=cal?GetTaxAmount(1000.00)
未完成{
case util.Success(TotalTaxResult(amount))=>
println(s“所得税总额$amount”)
case util.Success(TaxCalculationTimeout)=>
println(“计算税收超时”)
案例使用失败(ex)=>
println(s“计算税时出现异常:${ex.getMessage}”)
}

正如前面的答案所建议的,在这种情况下,你可能会发现撰写期货的能力很有帮助-我所知道的期货(和承诺,有些相关)的最佳描述如下:

这可能有助于解释可组合期货能够满足需求的方式,或许更多
val f = Source(workers)
  .mapAsync(USED_THREAD_COUNT)
    (actorRef => (actorRef ? QueryState).mapTo[StateResponse]))
  .runWith(Sink.seq)
f onComplete { responses => 
  // validate and work with responses
}