簡體   English   中英

包含Scala Futures修改列表的For循環

[英]For loop containing Scala Futures modifying a List

假設我有一個ListBuffer[Int]並使用foreach循環對其進行了迭代,並且每個循環都會從Future內部刪除此列表(刪除當前元素),並且當列表為空時會做一些特殊的事情。 示例代碼:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.collection.mutable.ListBuffer

val l = ListBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
l.foreach(n => Future {
  println(s"Processing $n")
  Future {
    l -= n
    println(s"Removed $n")
    if (l.isEmpty) println("List is empty!")
  }
})

這可能會非常糟糕地結束。 我有一個更復雜的代碼,具有相似的結構和相同的需求,但是我不知道如何構造它,因此我可以以更可靠的方式實現相同的功能。

您提出問題的方式實際上不在scala打算使用的功能范式中。

您似乎想要做的是列出一組異步計算,在每個計算的末尾執行某項操作,並在完成每個計算后執行其他操作。 如果您使用延續,則這非常簡單,可以通過Future上的mapflatMap方法輕松實現。

val fa: Future[Int] = Future { 1 } 
// will apply the function to the result when it becomes available
val fb: Future[Int] = fa.map(a => a + 1) 
// will start the asynchronous computation using the result when it will become available
val fc: Future[Int] = fa.flatMap(a => Future { a + 2 }) 

一旦擁有了所有這些功能,就可以在每個Future (成功)完成后輕松地執行一些操作:

val myFutures: List[Future[Int]] = ???
myFutures.map(futInt => futInt.map(int => int + 2))

在這里,我將對從List不同異步計算獲得的每個值加2。

您還可以使用Future.sequence選擇等待列表中的所有Future完成:

val myFutureList: Future[List[Int]] = Future.sequence(myFutures)

再一次,您將獲得Future ,當成功解析輸入列表中的每個Future時將解決該Future ,或者當您的Future之一失敗時將失敗。 然后,您將可以在此新的Future上使用mapflatMap ,以一次使用所有計算出的值。

因此,這就是我編寫您建議的代碼的方式:

val l = 1 to 10

val processings: Seq[Future[Unit]] = l.map {n =>
  Future(println(s"processing $n")).map {_ => 
    println(s"finished processing $n")
  }
}

val processingOver: Future[Unit] =
  Future.sequence(processings).map { (lu: Seq[Unit]) => 
    println(s"Finished processing ${lu.size} elements")
  }

當然,我建議您使用實函數而不是過程(返回Unit ),以便您可以使用值進行處理。 我用println編寫了一個代碼,該代碼將產生與您相同的輸出(除了印刷品,其含義略有不同,因為我們不再更改任何東西了)。

暫無
暫無

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

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