Scala 如何处理Akka Flow中的futures和mapAsync?

Scala 如何处理Akka Flow中的futures和mapAsync?,scala,concurrency,parallel-processing,akka,akka-stream,Scala,Concurrency,Parallel Processing,Akka,Akka Stream,我构建了一个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(GraphDS

我构建了一个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?否则。。。
谢谢

所以您正在尝试将来自f2和f4的结果合并在一起。在这种情况下,您尝试执行有时被称为“分散-聚集模式”的操作

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

  • 如果f2/f4出现故障,会发生什么情况
  • 如果时间太长怎么办
  • 每个输入记录都需要有唯一的键,以便知道f2的哪个输出对应于f4(反之亦然)

    • 对不起,我是阿克卡的新手,所以我还在学习。要获得预期的结果,一种方法是使用async:

      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})
      
      与:

      在这两个流程中,将实现您想要的

      不同的结果归结为
      mapsync
      map+async
      之间的关键区别。虽然
      mapAsync
      允许在并行线程中执行未来,但多个
      mapAsync
      流阶段仍由执行前执行的相同底层参与者管理(一般来说,为了成本效益)

      另一方面,
      async
      实际上在流中引入了一个异步边界,各个流阶段由单独的参与者处理。在您的例子中,两个流阶段中的每一个都独立地向下游发射元素,并且最先发射的元素首先被消耗。跨异步边界管理流不可避免地会有成本,Akka流使用窗口缓冲策略来分摊成本(见下图)

      有关
      mapsync
      async
      之间的差异的更多详细信息,这可能会引起兴趣

      map(_ + delta).async