2013-04-05 170 views
13

我知道我的问题看起来有点复杂。但我会尽力表达自己。如何等待异步任务在scala中完成?

我有这种方法,我想返回一个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返回为空。我不希望这是空的。

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

+0

如何将值追加到dataList如果它是一个VAL? – 2013-08-12 18:10:56

回答

25

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

小心执行在自己的遗嘱执行人阻塞期货,否则你最终会阻塞其它并行计算。这对于S2S和RPC请求尤其有用,其中阻塞有时是不可避免的。

+0

谢谢你的回答它帮助:)虽然我的解决方案得到它的工作是使用返回一个'Promise [Map [String,List [String]]]'当我打电话时,我检查了承诺的未来。在未来的成功之路上,我做了一些事情。也许我应该发布我的解决方案。如果是的话,让我知道。 – raxelsson 2013-04-08 07:49:37

+4

请发布您的解决方案,我感兴趣 – 2013-08-12 16:58:54

+0

@flavian谢谢 – 2013-08-12 20:10:36