访问 Scala 期货返回的值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17713642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Accessing value returned by scala futures
提问by user1822249
I am a newbie to scala futures and I have a doubt regarding the return value of scala futures.
我是 Scala 期货的新手,我对 Scala 期货的回报值有疑问。
So, generally syntax for a scala future is
所以,一般来说,scala 未来的语法是
def downloadPage(url: URL) = Future[List[Int]] {
}
I want to know how to access the List[Int]from some other method which calls this method.
我想知道如何List[Int]从调用此方法的其他方法访问。
In other words,
换句话说,
val result = downloadPage("localhost")
then what should be the approach to get List[Int]out of the future ?
那么List[Int]未来应该如何走出来呢?
I have tried using map method but not able to do this successfully.`
我曾尝试使用 map 方法,但无法成功做到这一点。`
回答by Alexey Romanov
The case of Success(listInt) => I want to return the listInt and I am not able to figure out how to do that.
Success(listInt) => 我想返回 listInt 的情况,但我无法弄清楚如何做到这一点。
The best practice is that you don'treturn the value. Instead you just pass the future (or a version transformed with map, flatMap, etc.) to everyone who needs this value and they can add their own onComplete.
最佳做法是不返回值。相反,你只是通过未来(或转化的版本map,flatMap等),大家谁需要这个价值,他们可以自己添加onComplete。
If you really need to return it (e.g. when implementing a legacy method), then the only thing you can do is to block (e.g. with Await.result) and you need to decide how long to await.
如果您确实需要返回它(例如在实现遗留方法时),那么您唯一能做的就是阻塞(例如使用Await.result)并且您需要决定等待多长时间。
回答by Noah
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 Futureinto the onCompletemethod, something like this:
理想情况下,如果您正在使用 a Future,您不想阻塞正在执行的线程,因此您会将处理您的结果的逻辑移动Future到onComplete方法中,如下所示:
result.onComplete({
case Success(listInt) => {
//Do something with my list
}
case Failure(exception) => {
//Do something with my error
}
})
回答by jfuentes
I hope you already solved this since it was asked in 2013 but maybe my answer can help someone else:
我希望你已经解决了这个问题,因为它在 2013 年被问到,但也许我的回答可以帮助别人:
If you are using Play Framework, it support async Actions (actually all Actions are async inside). An easy way to create an async Action is using Action.async(). You need to provide a Future[Result]to this function.
如果您使用的是 Play Framework,它支持异步 Actions(实际上所有 Actions 内部都是异步的)。创建异步操作的一种简单方法是使用Action.async(). 您需要Future[Result]为此功能提供一个。
Now you can just make transformations from your Future[List[Int]]to Future[Result]using Scala's map, flatMap, for-comprehension or async/await. Here an example from Play Framework documentation.
现在,你可以从您的转换Future[List[Int]]到Future[Result]使用Scala的地图,flatMap,换理解或异步/ AWAIT。这是 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))
}
回答by Akavall
You can do something like that. If The wait time that is given in Await.resultmethod is less than it takes the awaitableto execute, you will have a TimeoutException, and you need to handle the error (or any other error).
你可以做类似的事情。如果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"
}
}
回答by Priyank Desai
The best way I've found to think of a Future is a box that will, at some point, contain the thing that you want. The key thing with a Future is that you never open the box. Trying to force open the box will lead you to blocking and grief. Instead, you put the Future in another, larger box, typically using the map method.
我发现思考 Future 的最佳方式是一个盒子,它会在某个时候包含你想要的东西。Future 的关键是你永远不会打开盒子。试图强行打开盒子会导致你受阻和悲伤。相反,您将 Future 放在另一个更大的盒子中,通常使用 map 方法。
Here's an example of a Future that contains a String. When the Future completes, then Console.println is called:
下面是一个包含字符串的 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)
}
}
}
Note that in this case, we're calling the main method and then… finishing. The string's Future, provided by the global ExecutionContext, does the work of calling Console.println. This is great, because when we give up control over when someString is going to be there and when Console.println is going to be called, we let the system manage itself. In constrast, look what happens when we try to force the box open:
请注意,在这种情况下,我们正在调用 main 方法,然后……完成。字符串的 Future 由全局 ExecutionContext 提供,完成调用 Console.println 的工作。这很棒,因为当我们放弃对 someString 何时出现以及何时调用 Console.println 的控制时,我们让系统自行管理。相比之下,看看当我们尝试强制打开盒子时会发生什么:
val stringFuture: Future[String] = Future.successful("hello world!")
val someString = Future.await(stringFuture)
In this case, we have to wait — keep a thread twiddling its thumbs — until we get someString back. We've opened the box, but we've had to commandeer the system's resources to get at it.
在这种情况下,我们必须等待——保持一个线程在玩弄它的拇指——直到我们得到 someString 。我们已经打开了盒子,但我们不得不征用系统的资源来获得它。
回答by Johnny
It wasn't yet mentioned, so I want to emphasize the point of using Futurewith for-comprehension and the difference of sequential and parallel execution.
还没有提到,所以我想强调一下使用Futurefor-comprehension 以及顺序执行和并行执行的区别。
For example, for sequential execution:
例如,对于顺序执行:
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
}
And for parallel execution (note that the Futureare before the for-comprehension):
对于并行执行(请注意,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
}

