如akka streams documentation中所述,我试图建立一个工人池(流程):
def balancer[In, Out](worker: Flow[In, Out, NotUsed], workerCount: Int): Flow[In, Out, NotUsed] = {
import GraphDSL.Implicits._
Flow.fromGraph(GraphDSL.create() { implicit b =>
val balancer = b.add(Balance[In](workerCount))
val merge = b.add(Merge[Out](workerCount))
for (_ <- 1 to workerCount) {
balancer ~> worker ~> merge
}
FlowShape(balancer.in, merge.out)
})
}
然后我用这个函数并行运行流程:
def main(args: Array[String]) {
val system = ActorSystem()
implicit val mat = ActorMaterializer.create(system)
val flow = Flow[Int].map(e => {
println(e)
Thread.sleep(1000) // 1 second
e
})
Source(Range.apply(1, 10).toList)
.via(balancer(flow, 3))
.runForeach(e => {})
}
我得到预期的输出1, 2, 3, 4, 5, 6, 7, 8, 9
,但数字以每秒1的速率出现(没有并行性)。我做错了什么?
答案 0 :(得分:3)
该部分的文档已过时,将在下一版本中修复。基本上你只需要在流程本身上调用.async
。通过这样做,你可以在流程周围绘制一个“盒子”(你可以想象它是一个带有一个输入和输出端口的盒子),它可以防止在那个盒子上融合。通过这样做,基本上所有工人都将成为专职演员。图的其余部分(广播和合并阶段)将共享另一个actor(它们不会在不同的actor上运行,异步盒只保护流,外部的东西仍然会被融合)。
答案 1 :(得分:1)
正如Endre Varga指出的那样,流本身应标有.async
。
但即使这样,行为也不确定,因为异步阶段的默认缓冲区大小为16,而平衡器可能会将所有消息发送给同一个工作人员。
因此,balancer ~> worker.async.addAttributes(Attributes.inputBuffer(1, 1)) ~> merge
会导致所需的行为。
对于项目成员给出的答案,请参阅: https://github.com/akka/akka/issues/20146#issuecomment-201381356