【问题标题】:How do I wait for asynchronous tasks to complete in scala?如何在 scala 中等待异步任务完成?
【发布时间】:2013-03-28 01:59:29
【问题描述】:

我知道我的问题可能看起来有点复杂。但我会努力表达自己。

我有这个方法,我想返回一个充满数据的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
 }
}

我的代码可能没有使用最佳语法编写。

但我想要的是返回这个带有数据的 resultMap。 我的问题是,由于 "get to facebook url" 是异步完成的,所以这个 resultMap 返回为空。我当然不希望这是空的。

到目前为止,我方法中的这段代码是我的解决方案。显然,它不起作用,但我希望你能看到我正在尝试做的事情。即使您不确定,也可以随意回答您的想法,这可能会让我走上正轨。

【问题讨论】:

  • 如果 dataList 是 val,如何将值附加到?

标签: scala asynchronous map future


【解决方案1】:

使用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.
   };
};

另一种方法是Await 结果。 (这是一个阻塞动作)。

需要返回结果时使用

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);
};

小心在它们自己的执行器中执行阻塞期货,否则你最终会阻塞其他并行计算。

【讨论】:

  • 感谢您的回答,它帮助了 :) 虽然我的解决方案是使用返回 Promise[Map[String, List[String]]] 并且当我调用它时,我检查了承诺的未来。在那个未来的 onSuccess 上,我做了一些事情。也许我应该发布我的解决方案。如果有,请告诉我。
  • 如何在自己的执行器中执行阻塞函数?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-26
  • 2019-11-07
  • 1970-01-01
相关资源
最近更新 更多