我是scala期货的新手,我对scala期货的回报价值有疑问。
因此,scala未来的语法通常是
def downloadPage(url: URL) = Future[List[Int]] {
}
我想知道如何从调用此方法的其他方法访问List[Int]
。
换句话说,
val result = downloadPage("localhost")
那么将来List[Int]
的方法应该是什么?
我尝试过使用map方法,但无法成功完成此操作。
答案 0 :(得分:26)
成功案例(listInt)=>我想返回listInt,我无法弄清楚如何做到这一点。
最佳做法是不返回值。相反,您只需将未来(或使用map
,flatMap
等转换的版本)传递给需要此值的所有人,他们就可以添加自己的onComplete
。
如果你确实需要返回它(例如在实现遗留方法时),那么你唯一能做的就是阻止(例如用Await.result
),你需要决定等待多长时间。
答案 1 :(得分:11)
您需要等待将来完成以获得某个时间跨度的结果,这是可行的:
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
1}}方法,类似这样:
result.onComplete({
case Success(listInt) => {
//Do something with my list
}
case Failure(exception) => {
//Do something with my error
}
})
答案 2 :(得分:5)
我希望你已经解决了这个问题,因为它在2013年被问到了,但也许我的回答可以帮助其他人:
如果您使用的是Play Framework,它支持异步操作(实际上所有操作都是异步内部)。创建异步操作的简单方法是使用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))
}
答案 3 :(得分:5)
你可以做那样的事情。如果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"
}
}
答案 4 :(得分:3)
我发现想到未来的最佳方式是一个盒子,在某些时候,它会包含你想要的东西。未来的关键是你永远不会打开盒子。试图强行打开盒子将导致你阻塞和悲伤。相反,您通常使用map方法将Future放在另一个更大的框中。
以下是包含String的Future的示例。当Future完成时,则调用Console.println:
$results = $rets->Search(
'Property',
'Listing',
"(MatrixModifiedDT=1980-01-01T00:00:00+)",
["Limit"=>1]
);
请注意,在这种情况下,我们调用main方法然后...完成。由全局ExecutionContext提供的字符串的Future执行调用Console.println的工作。这很好,因为当我们放弃控制someString何时出现以及何时调用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)
}
}
}
在这种情况下,我们必须等待 - 让一个线程翻转它的拇指 - 直到我们得到someString。我们打开了这个盒子,但我们不得不征用系统的资源来获取它。
答案 5 :(得分:0)
尚未提及,因此我想强调结合使用Future
的理解和顺序执行与并行执行的区别。
例如,对于顺序执行:
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
在理解之前)
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
}