2013-04-05 4 views
13

제 문제가 조금 복잡해 보일 수도 있습니다. 그러나 나는 자신을 잘 표현하려고 노력할 것입니다.비동기 작업이 스칼라에서 완료 될 때까지 어떻게 대기합니까?

데이터로 채워진 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 인 경우 어떻게 값을 dataList에 추가 할 수 있습니까? –

답변

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 감사합니다 –

관련 문제