簡體   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