web-dev-qa-db-ja.com

scala futuresによって返される値にアクセスする

私はscala futuresの初心者であり、scala futures。

したがって、一般的にscala futureの構文は

 def downloadPage(url: URL) = Future[List[Int]] {

 }

このメソッドを呼び出す他のメソッドからList[Int]にアクセスする方法を知りたい。

言い換えると、

val result = downloadPage("localhost") 

List[Int]を未来から抜け出すためのアプローチは何でしょうか?

マップメソッドを使用しようとしましたが、これを正常に実行できませんでした。

42
user1822249

Success(listInt)の場合=> listIntを返したいのですが、その方法がわかりません。

ベストプラクティスは、値を返さないことです。代わりに、この値を必要とするすべての人に未来(またはmapflatMapなどで変換されたバージョン)を渡すだけで、独自のonCompleteを追加できます。

あなたが本当にそれを返す必要がある場合(例えば、レガシーメソッドを実装するとき)、あなたができる唯一のことはブロックすることです(例えば、 Await.result )そして、待機する時間を決定する必要があります。

25
Alexey Romanov

いくつかのタイムスパンを与えられた結果を得るために未来が完了するのを待つ必要があります、ここでうまくいくものがあります:

  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
    }
  })
12
Noah

2013年に依頼されたので、これを既に解決していただければ幸いですが、私の答えが他の誰かに役立つかもしれません。

Play Frameworkを使用している場合、非同期アクションをサポートしています(実際、すべてのアクションは内部で非同期です)。非同期アクションを作成する簡単な方法は、Action.async()を使用することです。この関数にFuture[Result]を提供する必要があります。

これで、Scalaのマップ、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))
}
6
jfuentes

あなたはそのようなことをすることができます。 Await.resultメソッドで指定された待機時間が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"
        }
}
5
Akavall

私が未来を考えるために見つけた最良の方法は、ある時点であなたが望むものを含む箱です。 Futureで重要なことは、決して箱を開けないことです。箱を無理やり開けようとすると、ブロッキングと悲しみにつながります。代わりに、通常mapメソッドを使用して、Futureを別の大きなボックスに入れます。

文字列を含む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メソッドを呼び出してから...終了することに注意してください。グローバルExecutionContextによって提供される文字列のFutureは、Console.printlnを呼び出す作業を行います。 someStringが存在するタイミングとConsole.printlnが呼び出されるタイミングの制御を断念するとき、システムが自分自身を管理できるため、これは素晴らしいことです。対照的に、ボックスを強制的に開こうとするとどうなるかを見てください。

val stringFuture: Future[String] = Future.successful("hello world!")
val someString = Future.await(stringFuture)

この場合、someStringを取得するまで待機する必要があります(スレッドが親指をいじるのを維持する)。箱を開けましたが、それに到達するにはシステムのリソースを指揮する必要がありました。

3
Priyank Desai