2013-04-05 3 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

Как вы можете добавить значения в список данных, если это значение val? –

ответ

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]]]», и когда я его назвал, я проверил будущее обещаний. И в этом будущем onSuccess я сделал что-то. Может быть, я должен опубликовать свое решение. Если да, дайте мне знать. – raxelsson

+4

, пожалуйста, напишите свое решение, меня интересует –

+0

@flavian спасибо –