私はscala futuresの初心者であり、scala futures。
したがって、一般的にscala futureの構文は
def downloadPage(url: URL) = Future[List[Int]] {
}
このメソッドを呼び出す他のメソッドからList[Int]
にアクセスする方法を知りたい。
言い換えると、
val result = downloadPage("localhost")
List[Int]
を未来から抜け出すためのアプローチは何でしょうか?
マップメソッドを使用しようとしましたが、これを正常に実行できませんでした。
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を使用している場合、非同期アクションをサポートしています(実際、すべてのアクションは内部で非同期です)。非同期アクションを作成する簡単な方法は、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))
}
あなたはそのようなことをすることができます。 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"
}
}
私が未来を考えるために見つけた最良の方法は、ある時点であなたが望むものを含む箱です。 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を取得するまで待機する必要があります(スレッドが親指をいじるのを維持する)。箱を開けましたが、それに到達するにはシステムのリソースを指揮する必要がありました。