2013-04-05 14 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ありがとう –

関連する問題