我是 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
.
如果您确实需要返回它(例如,在实现旧方法时),那么您唯一能做的就是阻止(例如 with Await.result
)并且您需要决定等待多长时间。
You need to wait for the future to complete to get the result given some timespan, here's something that would work:
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)
Ideally, if you're using a Future
, you don't want to block the executing thread, so you would move your logic that deals with the result of your Future
into the onComplete
method, something like this:
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
执行所需的时间,您将有一个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 完成时,将调用 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。我们已经打开了盒子,但我们必须征用系统的资源才能拿到它。
还没有提到,所以我想强调一下使用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
理解之前):
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
}