[英]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
上的map
和flatMap
方法輕松實現。
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
上使用map
或flatMap
,以一次使用所有計算出的值。
因此,這就是我編寫您建議的代碼的方式:
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.