如何在 Scala 中等待异步任务完成?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15837561/
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
How do I wait for asynchronous tasks to complete in scala?
提问by malmling
I'm aware that my problem might seem a little bit complex. But I'll try to express myself well.
我知道我的问题可能看起来有点复杂。但我会尽量表达好自己。
I have this method which I want to return a Map[String, List[String]]filled with data.
我有这个方法,我想返回一个Map[String, List[String]]填充数据。
def myFunction():Map[String, List[String]] = {
val userMap = Map[String, String](("123456", "ASDBYYBAYGS456789"),
("54321", "HGFDSA5432"))
//the result map to return when all data is collected and added
val resultMap:Future[Map[String, List[String]]]
//when this map is finished (filled) this map is set to resultMap
val progressMap = Map[String, List[String]]()
for(user <- userMap){
//facebook graph API call to get posts.
val responsePost = WS.url("async get to facebook url").get()
responsePosts.flatMap { response =>
val jsonBody = response.json
val dataList = List[String]()
for(i <-0 until 5){
//parse the json-data to strings
val messages = (jsonBody.\("statuses").\("data")(i).\("message"))
val likesArray = (jsonBody.\("statuses").\("data")(i).\("data")).flatMap(_.as[List[JsObject]])
val likes = likesArray.length
//Put post with likes in temporary list
dataList ::= ?("Post: " + message.toString + " Likes: " + likes.toString)
}
//facebook graph API call to get friends.
val responseFriends = WS.url("async get to facebook url").get()
responseFriends.map { response =>
val jsonBody = response.json
val friendCount = jsonBody.\("data")(0).\("friend_count").toString
//add "Friends: xxx" to the dataList and add the new row to resultMap containig a list with post and friends.
dataList ::= ("Friends: " + friendCount)
progressMap += user._1 -> dataList
//check if all users has been updated
if(progressMap.size == userMap.size){
resultMap = progressMap
}
}
}
}
//return the resultMap.
return resultMap
}
}
My code might not be written with optimal syntax.
我的代码可能不是用最佳语法编写的。
But what I want is to return this resultMap with data.
My problem is that since the "get to facebook url"is done asynchronously this resultMap is returned empty. I do not want this to be empty ofcourse.
但我想要的是用数据返回这个 resultMap 。我的问题是,由于"get to facebook url"异步完成,因此 resultMap 返回空。我当然不希望这是空的。
This code in my method is my solution so far. It does not work, obviously, but I hope you can see what I'm trying to do. Feel free to answer with your thoughts even though youre not sure, it might put me on the right track.
到目前为止,我方法中的这段代码是我的解决方案。显然,它不起作用,但我希望你能明白我在做什么。即使您不确定,也可以随意回答您的想法,这可能会让我走上正确的轨道。
回答by flavian
Use scala.concurrent.{Future, Promise}:
使用scala.concurrent.{Future, Promise}:
def doAsyncAction: Promise[T] = {
val p = Promise[T]
p success doSomeOperation
p
}
def useResult = {
val async = doAsyncAction;
// The return of the below is Unit.
async.future onSuccess {
// do action.
};
};
Another way is to Awaitthe result. (this is a blocking action).
另一种方法是Await结果。(这是一个阻塞操作)。
Used when you need to return the result
需要返回结果时使用
import scala.concurrent.{ ExecutionContext, ExecutionContext$, Future, Promise, Await }
import scala.concurrent.duration._
def method: Option[T] = {
val future: Future[T] = Future {
someAction
}
val response = future map {
items => Some(items)
} recover {
case timeout: java.util.concurrent.TimeoutException => None
}
Await.result(future, 5000 millis);
};
Be careful to execute blocking Futures in their own executor, otherwise you end up blocking other parallel computation.
小心在它们自己的执行器中执行阻塞 Futures,否则你最终会阻塞其他并行计算。

