我很难理解akka-stream是否在一个分支的广播中花费大量时间(异步)在图表上对Source施加反压。
我尝试了buffer
和batch
来查看源上是否施加了任何背压,但看起来却不是这样。我还尝试了刷新System.out
,但是它并没有改变任何东西。
object Test extends App {
/* Necessary for akka stream */
implicit val system = ActorSystem("test")
implicit val materializer: ActorMaterializer = ActorMaterializer()
val g = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>
import GraphDSL.Implicits._
val in = Source.tick(0 seconds, 1 seconds, 1)
in.runForeach(i => println("Produced " + i))
val out = Sink.foreach(println)
val out2 = Sink.foreach[Int]{ o => println(s"2 $o") }
val bcast = builder.add(Broadcast[Int](2))
val batchedIn: Source[Int, Cancellable] = in.batch(4, identity) {
case (s, v) => println(s"Batched ${s+v}"); s + v
}
val f2 = Flow[Int].map(_ + 10)
val f4 = Flow[Int].map { i => Thread.sleep(2000); i}
batchedIn ~> bcast ~> f2 ~> out
bcast ~> f4.async ~> out2
ClosedShape
})
g.run()
}
当我运行程序时,我希望在控制台中看到“ Batched ...”(批处理...),并且由于f4的处理速度不够快,有时会使其暂时卡住。目前,由于连续生成数字并且不进行批处理,因此这些行为均不符合预期。
编辑:我注意到一段时间后,批处理消息开始在控制台中打印出来。我仍然不知道为什么它不会很快发生,因为第一个元素应该发生背压
答案 0 :(得分:1)
解释此行为的原因是当设置异步边界时akka引入了内部缓冲区。
Buffers for asynchronous operators
使用异步运算符时作为优化引入的内部缓冲区。
虽然流水线通常会提高吞吐量,但实际上,传递元素穿过异步(并因此跨越线程)边界的成本非常高。为了摊销此成本,Akka Streams在内部使用了窗口化的批量反压策略。之所以要窗口化,是因为与Stop-And-Wait协议相反,多个元素可能与请求元素同时“进行中”。这也是批量处理的,因为一旦从窗口缓冲区中清空了一个元素,就不会立即请求一个新元素,而在清空多个元素之后,会请求多个元素。这种批处理策略降低了通过异步边界传播背压信号的通信成本。
我知道这是玩具流,但是如果您解释您的目标是什么,我会尽力帮助您。
您需要mapAsync
而不是async
val g = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>
import akka.stream.scaladsl.GraphDSL.Implicits._
val in = Source.tick(0 seconds, 1 seconds, 1).map(x => {println(s"Produced ${x}"); x})
val out = Sink.foreach[Int]{ o => println(s"F2 processed $o") }
val out2 = Sink.foreach[Int]{ o => println(s"F4 processed $o") }
val bcast = builder.add(Broadcast[Int](2))
val batchedIn: Source[Int, Cancellable] = in.buffer(4,OverflowStrategy.backpressure)
val f2 = Flow[Int].map(_ + 10)
val f4 = Flow[Int].mapAsync(1) { i => Future { println("F4 Started Processing"); Thread.sleep(2000); i }(system.dispatcher) }
batchedIn ~> bcast ~> f2 ~> out
bcast ~> f4 ~> out2
ClosedShape
}).run()