2013-04-05 10 views
13

Jestem świadomy, że mój problem może wydawać się nieco skomplikowany. Ale spróbuję wyrazić siebie dobrze.Jak mogę czekać na wykonanie asynchronicznych zadań w scala?

Mam tę metodę, którą chcę zwrócić Map[String, List[String]] wypełniony danymi.

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

Mój kod może nie być zapisany z optymalną składnią.

Ale chcę zwrócić ten wynikMap z danymi. Mój problem polega na tym, że ponieważ "get to facebook url" jest wykonywany asynchronicznie, wynik resultMap jest zwracany jako pusty. Nie chcę, żeby to było puste.

Ten kod w mojej metodzie jest moim rozwiązaniem. To oczywiście nie działa, ale mam nadzieję, że widzisz, co próbuję zrobić. Nie wahaj się odpowiedzieć swoimi myślami, nawet jeśli nie jesteś pewien, może to postawić mnie na właściwej drodze.

+0

jak dodać wartości do listy danych, jeśli jest to wartość? –

Odpowiedz

25

Zastosowanie 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. 
    }; 
}; 

Innym sposobem jest Await wynik. (jest to działanie blokujące).

Używane, gdy trzeba zwrócić wynik

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

Należy uważać, aby wykonać blokowanie Futures we własnym wykonawca, inaczej skończy się blokowanie innych obliczeń równoległych. Jest to szczególnie przydatne w przypadku żądań S2S i RPC, w których blokowanie jest czasem niemożliwe do uniknięcia.

+0

Dziękuję za odpowiedź, która pomogła :) Chociaż moim rozwiązaniem, które sprawiło, że zadziałało, było użycie zwrotu "Promise [Map [String, List [String]]]" i kiedy zadzwoniłem, sprawdziłem przyszłość obietnic. I w tym sukcesie na przyszłość zrobiłem coś. Może powinienem opublikować moje rozwiązanie. Jeśli tak, daj mi znać. – raxelsson

+4

proszę wysłać swoje rozwiązanie, jestem zainteresowany –

+0

@flavian dziękuję –

Powiązane problemy