2013-04-05 12 views
13

Sono consapevole che il mio problema potrebbe sembrare un po 'complesso. Ma cercherò di esprimermi bene.Come attendere il completamento di attività asincrone in scala?

Ho questo metodo che voglio restituire un Map[String, List[String]] pieno di dati.

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

Il mio codice potrebbe non essere scritto con sintassi ottimale.

Ma quello che voglio è restituire questo risultatoMappa con dati. Il mio problema è che poiché lo "get to facebook url" viene eseguito in modo asincrono, questo risultato viene restituito vuoto. Non voglio che questo sia vuoto di corso.

Questo codice nel mio metodo è la mia soluzione finora. Ovviamente non funziona, ma spero che tu possa vedere cosa sto cercando di fare. Sentiti libero di rispondere con i tuoi pensieri anche se non sei sicuro, potrebbe mettermi sulla strada giusta.

+0

come si possono aggiungere valori a dataList se si tratta di una val? –

risposta

25

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

Un altro modo è quello di Await il risultato. (questa è un'azione di blocco).

Utilizzato quando è necessario restituire il risultato

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

Fare attenzione ad eseguire il blocco Futures nel proprio esecutore, altrimenti si finisce per bloccare altre calcolo parallelo. Ciò è particolarmente utile per le richieste S2S e RPC, dove il blocco a volte non è evitabile.

+0

Grazie per la risposta che ha aiutato :) Anche se la mia soluzione che ha funzionato è stato utilizzare un ritorno a "Promise [Map [String, List [String]]" e quando l'ho chiamato ho controllato il futuro di quel promesse. E in quel futuro di successo, ho fatto qualcosa. Forse dovrei pubblicare la mia soluzione. Se è così fammi sapere. – raxelsson

+4

per favore pubblica la tua soluzione, sono interessato –

+0

@flavian grazie –

Problemi correlati