繁体   English   中英

你如何应对Akka Flow中的期货和mapAsync?

[英]How do you deal with futures and mapAsync in Akka Flow?

我构建了一个定义简单流程的akka​​图形DSL。 但是流f4需要3秒才能发送一个元素,而f2需要10秒。

结果,我得到了:3,2,3,2。但是,这不是我想要的。 由于f2花费了太多时间,我想得到:3,3,2,2。这是代码......

implicit val actorSystem = ActorSystem("NumberSystem")
implicit val materializer = ActorMaterializer()

val g = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>
  import GraphDSL.Implicits._
  val in = Source(List(1, 1))
  val out = Sink.foreach(println)

  val bcast = builder.add(Broadcast[Int](2))
  val merge = builder.add(Merge[Int](2))



  val yourMapper: Int => Future[Int] = (i: Int) => Future(i + 1)
  val yourMapper2: Int => Future[Int] = (i: Int) => Future(i + 2)

  val f1, f3 = Flow[Int]
  val f2= Flow[Int].throttle(1, 10.second, 0, ThrottleMode.Shaping).mapAsync[Int](2)(yourMapper)
  val f4= Flow[Int].throttle(1, 3.second, 0, ThrottleMode.Shaping).mapAsync[Int](2)(yourMapper2)

  in ~> f1 ~> bcast ~> f2 ~> merge ~> f3 ~> out
  bcast ~> f4 ~> merge
  ClosedShape
})
g.run()

那我哪里错了? 使用future或mapAsync? 或者......谢谢

对不起,我是akka的新人,所以我还在学习。 要获得预期的结果,一种方法是将异步:

val g = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>
  import GraphDSL.Implicits._
  val in = Source(List(1, 1))
  val out = Sink.foreach(println)

  val bcast = builder.add(Broadcast[Int](2))
  val merge = builder.add(Merge[Int](2))



  val yourMapper: Int => Future[Int] = (i: Int) => Future(i + 1)
  val yourMapper2: Int => Future[Int] = (i: Int) => Future(i + 2)

  val f1, f3 = Flow[Int]
  val f2= Flow[Int].throttle(1, 10.second, 0, ThrottleMode.Shaping).map(_+1)
    //.mapAsyncUnordered[Int](2)(yourMapper)
  val f4= Flow[Int].throttle(1, 3.second, 0, ThrottleMode.Shaping).map(_+2)
    //.mapAsync[Int](2)(yourMapper2)

  in ~> f1 ~> bcast ~> f2.async ~> merge ~> f3 ~> out
  bcast ~> f4.async ~> merge
  ClosedShape
})
g.run()

正如您已经想到的那样,替换:

mapAsync(i => Future{i + delta})

有:

map(_ + delta).async

在这两个流程中将实现你想要的。

不同的结果归结为mapAsyncmap + async之间的关键区别。 虽然mapAsync允许在并行线程中执行Futures,但是多个mapAsync流阶段仍然由相同的底层actor执行,这将在执行之前执行运算符融合 (通常为了成本效率)。

另一方面, async实际上在流流中引入了异步边界,各个流阶段由不同的actor处理。 在您的情况下,两个流动阶段中的每一个独立地向下游发射元素,并且首先消耗的元素首先被消耗。 不可避免地需要跨异步边界管理流的成本,Akka Stream使用窗口缓冲策略来摊销成本(参见Akka Stream doc )。

有关详细信息: mapAsyncasync之间的mapAsync ,此博客文章可能会引起关注。

所以你试图将f2和f4的结果连接在一起。 在这种情况下,您正在尝试执行有时称为“分散聚集模式”的操作。

我不认为有现成的方法来实现它,没有添加一个自定义的有状态阶段,将跟踪f2和f4的输出,并在两者都可用时发出记录。 但是要记住它们是一些复杂问题:

  • 如果f2 / f4失败会发生什么
  • 如果他们花了太长时间会发生什么
  • 您需要为每个输入记录设置唯一键,以便知道f2的哪个输出对应于f4(反之亦然)

暂无
暂无

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

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