I have RunnableGraph
like following. When there is simple map
between broadcast
and merge
stages everything is fine. However, when it comes to mapConcat
, this code is not working after consuming the first element.
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. Consider the following chain of events:
mapConcat
function prints List(2,2,2)
mapConcat
stage needs demand to emit the first of the 3 available elements (2, 2, 2) Sink.ignore
(that never backpressures), and the mapConcat
itself. mapConcat
backpressures if "there are still remaining elements from the previously calculated collection", as per the docs . 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. 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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.