簡體   English   中英

為了理解:如何順序運行期貨

[英]For comprehension: how to run Futures sequentially

鑒於以下方法......

def doSomething1: Future[Int] = { ... }
def doSomething2: Future[Int] = { ... }
def doSomething3: Future[Int] = { ... }

......以及以下的理解:

for {
  x <- doSomething1
  y <- doSomething2
  z <- doSomething3
} yield x + y + z

這三種方法並行運行,但在我的情況下, doSomething2必須在doSomething1完成后運行。 如何按順序運行這三種方法?

編輯

正如Philosophus42所建議的,下面是doSomething1的可能實現:

def doSomething1: Future[Int] = {
  // query the database for customers younger than 40;
  // `find` returns a `Future` containing the number of matches
  customerService.find(Json.obj("age" -> Json.obj("$lt" -> 40)))
}

...所以Future是通過對另一個方法的內部調用創建的。

編輯2

也許我過分簡化了用例......我很抱歉。 讓我們再試一次,更接近真實的用例。 以下是三種方法:

for {
  // get all the transactions generated by the exchange service
  transactions <- exchange.orderTransactions(orderId)

  //for each transaction create a log
  logs <- Future.sequence(tansactions.map { transaction =>
    for {
      // update trading order status
      _ <- orderService.findAndUpdate(transaction.orderId, "Executed")

      // create new log
      log <- logService.insert(Log(
        transactionId => transaction.id,
        orderId => transaction.orderId,
        ...
      ))
    } yield log
  })
} yield logs

我要做的是為與訂單關聯的每個事務創建一個日志。 即使transactions只包含一個條目,也會多次調用logService.insert

評論你的帖子

首先, doSomethingX中的代碼如何? 更令人討厭的是,使用您給定的代碼,期貨並行運行。

回答

為了使Future執行順序,只需使用

for {
  v1 <- Future { ..block1... } 
  v2 <- Future { ..block2... } 
} yield combine(v1, v2)

這個工作的原因是,語句Future {..body ..}啟動異步計算,在那個時間點評估語句。

隨着上面的理解,desugared

Future { ..block1.. }
  .flatMap( v1 => 
     Future { ..block>.. }
       .map( v2 => combine(v1,v2) )
  )

很明顯,那

  • 如果Future{ ...block1... }有結果,
  • flatMap方法被觸發,其中
  • 然后觸發Future { ...block2... }

因此Future { ...block2... } Future { ...block1... } 之后執行

附加信息

Future

Future { 
  <block> 
} 

通過ExecutionContext 立即觸發包含塊的ExecutionContext

小片1:

val f1 = Future { <body> }
val f2 = Future { <otherbody> }

這兩個計算是並行運行的(如果你的ExecutionContext是這樣設置的),因為這兩個值是立即計算的。

摘錄2:

構造

def f1 = Future { ..... }

一旦f1被調用,將開始執行未來

編輯:

j3d,我仍然感到困惑,為什么你的代碼沒有按預期工作,如果你的語句是正確的,那么Future 是在 computeSomethingX方法中創建的。

這是一個代碼片段,證明, computeSomething2是在computeSomething1之后執行的

import scala.concurrent。{Await,Future} import scala.concurrent.duration._

object Playground {

  import scala.concurrent.ExecutionContext.Implicits.global

  def computeSomething1 : Future[Int] = {
    Future {
      for (i <- 1 to 10) {
        println("computeSomething1")
        Thread.sleep(500)
      }
      10
    }
  }

  def computeSomething2 : Future[String] = {
    Future {
      for(i <- 1 to 10) {
        println("computeSomething2")
        Thread.sleep(800)
      }
      "hello"
    }
  }

  def main(args: Array[String]) : Unit = {

    val resultFuture: Future[String] = for {
      v1 <- computeSomething1
      v2 <- computeSomething2
    } yield v2 + v1.toString

    // evil "wait" for result

    val result = Await.result(resultFuture, Duration.Inf)

    println( s"Result: ${result}")
  }
}

與輸出

computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
Result: hello10

編輯2

如果您希望它們並行執行,請事先創建期貨(此處為f1f2

def main(args: Array[String]) : Unit = {
  val f1 = computeSomething1
  val f2 = computeSomething2

  val resultFuture: Future[String] = for {
    v1 <- f1
    v2 <- f2
  } yield v2 + v1.toString

  // evil "wait" for result

  val result = Await.result(resultFuture, Duration.Inf)

  println( s"Result: ${result}")
}

我看到兩個變種來實現這個目標:

第一:確保期貨是在理解范圍內創建的。 這意味着你的函數應該像這樣定義: def doSomething1: Future[Int] = Future { ... } 在這種情況下,for comprehension應按順序執行Futures。

第二:在其他人開始之前使用你需要完成的Future的地圖功能:

doSomething1.map{ i =>
  for {
  y <- doSomething2
  z <- doSomething3
  } yield i + y + z
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM