簡體   English   中英

訪問 Scala 期貨返回的值

[英]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 的情況,但我無法弄清楚如何做到這一點。

最佳做法是返回值。 相反,您只需將未來(或使用mapflatMap等轉換的版本)傳遞給需要此值的每個人,他們就可以添加自己的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.

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