简体   繁体   English

Akka流mapConcat不适用于循环的RunnableGraph

[英]Akka-streams mapConcat not working with cycled RunnableGraph

I have RunnableGraph like following. 我有如下的RunnableGraph When there is simple map between broadcast and merge stages everything is fine. broadcastmerge阶段之间有简单的map ,一切都很好。 However, when it comes to mapConcat , this code is not working after consuming the first element. 但是,当涉及mapConcat ,使用第一个元素后此代码将无法正常工作。

I want to know why it doesn't work. 我想知道为什么它不起作用。

RunnableGraph.fromGraph(GraphDSL.create() { implicit b =>
import GraphDSL.Implicits._

val M = b.add(MergePreferred[Int](1))
val B = b.add(Broadcast[Int](2))
val S = Source(List(3))

S ~> M ~> Flow[Int].map { s => println(s); s } ~> B ~> Sink.ignore
M.preferred <~ Flow[Int].map(x => List.fill(3)(x-1)).mapConcat(x => {println(x); x}).filter(_ > 0)  <~ B
ClosedShape 
}) 

// run() output: 
// 3
// List(2,2,2)

The mapConcat stage blocks the feedback loop, and that is expected. mapConcat阶段阻止了反馈循环,这是预期的。 Consider the following chain of events: 考虑以下事件链:

  1. the mapConcat function prints List(2,2,2) mapConcat函数打印List(2,2,2)
  2. the mapConcat stage needs demand to emit the first of the 3 available elements (2, 2, 2) mapConcat阶段需要发出3个可用元素( mapConcat的第一个的需求
  3. the demand has to come from the Merge stage, and therefore from the Broadcast stage. 需求必须来自合并阶段,因此来自广播阶段。
  4. the Broadcast stage backpressures if any of its downstreams backpressures. 广播级的背压(如果其下游有任何背压)。 It's downstreams are a Sink.ignore (that never backpressures), and the mapConcat itself. 它的下游是Sink.ignore (永不背压)和mapConcat本身。
  5. the mapConcat backpressures if "there are still remaining elements from the previously calculated collection", as per the docs . mapConcat背压,如果“是否仍有从先前计算的收集要素”,按照该文档 This is indeed the case. 确实是这样。

In other words, your cycle is unbalanced. 换句话说,您的周期是不平衡的。 You are introducing more elements in the feedback loop than you are removing. 您在反馈循环中引入的元素要多于要删除的元素。

This issue is explained in detail in this documentation page , where a couple of solutions are also presented. 本文档页面中详细解释了此问题,其中还提供了一些解决方案。 For your specific case, because of the filter stage you have, introducing a buffer larger than 13 would print all the elements. 对于您的特定情况,由于您具有过滤器阶段,因此引入大于13的缓冲区将打印所有元素。 However, note that the graph will just hang and not complete afterwards. 但是,请注意,该图形将只是挂起,并且此后不会完成。

S ~> M ~> Flow[Int].map { s => println(s); s } ~> B ~> Sink.ignore
M.preferred <~ Flow[Int].buffer(20, OverflowStrategy.dropHead) <~ Flow[Int].map(x => List.fill(3)(x-1)).mapConcat(x => {println(x); x}).filter(_ > 0)  <~ B

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM