[英]Accessing value returned by scala futures
我是 Scala 期貨的新手,我對 Scala 期貨的回報值有疑問。
所以,一般來說,scala 未來的語法是
def downloadPage(url: URL) = Future[List[Int]] {
}
我想知道如何從調用此方法的其他方法訪問List[Int]
。
換句話說,
val result = downloadPage("localhost")
那么讓List[Int]
脫離未來的方法應該是什么?
我曾嘗試使用 map 方法,但無法成功做到這一點。`
Success(listInt) => 我想返回 listInt 的情況,但我無法弄清楚如何做到這一點。
最佳做法是不返回值。 相反,您只需將未來(或使用map
、 flatMap
等轉換的版本)傳遞給需要此值的每個人,他們就可以添加自己的onComplete
。
如果你真的需要返回它(例如在實現一個遺留方法時),那么你唯一能做的就是阻塞(例如使用Await.result
)並且你需要決定等待多長時間。
您需要等待未來完成才能獲得給定時間跨度的結果,這里有一些可行的方法:
import scala.concurrent.duration._
def downloadPage(url: URL) = Future[List[Int]] {
List(1,2,3)
}
val result = downloadPage("localhost")
val myListInt = result.result(10 seconds)
理想情況下,如果您使用的是Future
,您不想阻塞正在執行的線程,因此您會將處理Future
結果的邏輯移動到onComplete
方法中,如下所示:
result.onComplete({
case Success(listInt) => {
//Do something with my list
}
case Failure(exception) => {
//Do something with my error
}
})
我希望你已經解決了這個問題,因為它在 2013 年被問到,但也許我的回答可以幫助別人:
如果您使用的是 Play Framework,它支持異步 Actions(實際上所有 Actions 內部都是異步的)。 創建異步操作的一種簡單方法是使用Action.async()
。 您需要為此函數提供Future[Result]
。
現在,您可以使用 Scala 的 map、flatMap、for-comprehension 或 async/await 將Future[List[Int]]
為Future[Result]
。 這是 Play Framework 文檔中的示例。
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def index = Action.async {
val futureInt = scala.concurrent.Future { intensiveComputation() }
futureInt.map(i => Ok("Got result: " + i))
}
你可以做類似的事情。 如果Await.result
方法中給出的等待時間小於執行awaitable
所需的awaitable
,則會出現TimeoutException
,並且您需要處理錯誤(或任何其他錯誤)。
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
import scala.concurrent.duration._
object MyObject {
def main(args: Array[String]) {
val myVal: Future[String] = Future { silly() }
// values less than 5 seconds will go to
// Failure case, because silly() will not be done yet
Try(Await.result(myVal, 10 seconds)) match {
case Success(extractedVal) => { println("Success Happened: " + extractedVal) }
case Failure(_) => { println("Failure Happened") }
case _ => { println("Very Strange") }
}
}
def silly(): String = {
Thread.sleep(5000)
"Hello from silly"
}
}
我發現思考 Future 的最佳方式是一個盒子,它會在某個時候包含你想要的東西。 Future 的關鍵在於你永遠不會打開盒子。 試圖強行打開盒子會導致你受阻和悲傷。 相反,您將 Future 放在另一個更大的盒子中,通常使用 map 方法。
下面是一個包含字符串的 Future 示例。 當 Future 完成時,Console.println 被調用:
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object Main {
def main(args:Array[String]) : Unit = {
val stringFuture: Future[String] = Future.successful("hello world!")
stringFuture.map {
someString =>
// if you use .foreach you avoid creating an extra Future, but we are proving
// the concept here...
Console.println(someString)
}
}
}
請注意,在這種情況下,我們正在調用 main 方法,然后……完成。 字符串的 Future 由全局 ExecutionContext 提供,完成調用 Console.println 的工作。 這很好,因為當我們放棄對 someString 何時出現以及何時調用 Console.println 的控制時,我們讓系統自行管理。 相比之下,看看當我們嘗試強制打開盒子時會發生什么:
val stringFuture: Future[String] = Future.successful("hello world!")
val someString = Future.await(stringFuture)
在這種情況下,我們必須等待——保持一個線程在玩弄它的拇指——直到我們得到 someString 。 我們已經打開了盒子,但我們不得不征用系統的資源來獲得它。
還沒有提到,所以我想強調一下使用Future
with for-comprehension 以及順序和並行執行的區別。
例如,對於順序執行:
object FuturesSequential extends App {
def job(n: Int) = Future {
Thread.sleep(1000)
println(s"Job $n")
}
val f = for {
f1 <- job(1)
f2 <- job(2)
f3 <- job(3)
f4 <- job(4)
f5 <- job(5)
} yield List(f1, f2, f3, f4, f5)
f.map(res => println(s"Done. ${res.size} jobs run"))
Thread.sleep(6000) // We need to prevent main thread from quitting too early
}
對於並行執行(注意Future
在 for-comprehension 之前):
object FuturesParallel extends App {
def job(n: Int) = Future {
Thread.sleep(1000)
println(s"Job $n")
}
val j1 = job(1)
val j2 = job(2)
val j3 = job(3)
val j4 = job(4)
val j5 = job(5)
val f = for {
f1 <- j1
f2 <- j2
f3 <- j3
f4 <- j4
f5 <- j5
} yield List(f1, f2, f3, f4, f5)
f.map(res => println(s"Done. ${res.size} jobs run"))
Thread.sleep(6000) // We need to prevent main thread from quitting too early
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.