7

私にはいくつかの先物があります。CampaignFuture は List[BigInt] を返します。最初のリストから返されたリストの各値に対して、2 番目の将来の profileFuture を呼び出せるようにしたいと考えています。2 番目の Future は、最初の Future が完了したときにのみ呼び出すことができます。Scalaでこれを達成するにはどうすればよいですか?

campaignFuture(1923).flatMap?? (May be?)

def campaignFuture(advertiserId: Int): Future[List[BigInt]] = Future {
  val campaignHttpResponse = getCampaigns(advertiserId.intValue())
  parseProfileIds(campaignHttpResponse.entity.asString)
}

def profileFuture(profileId: Int): Future[List[String]] = Future {
  val profileHttpResponse = getProfiles(profileId.intValue())
  parseSegmentNames(profileHttpResponse.entity.asString)
}    
4

1 に答える 1

4

List と Future が混在しているため、ここでは for 内包表記は適用できません。だから、あなたの友達は map と flatMap です:

将来の結果に反応する

  import scala.concurrent.{Future, Promise, Await}
  import scala.concurrent.duration.Duration
  import scala.concurrent.ExecutionContext.Implicits.global

  def campaignFuture(advertiserId: Int): Future[List[BigInt]] = Future {
    List(1, 2, 3)
  }
  def profileFuture(profileId: Int): Future[List[String]] = {
    // delayed Future
    val p = Promise[List[String]]
    Future {
      val delay: Int = (math.random * 5).toInt
      Thread.sleep(delay * 1000)
      p.success(List(s"profile-for:$profileId", s"delayed:$delay sec"))
    }
    p.future
  }



  // Future[List[Future[List[String]]]
  val listOfProfileFuturesFuture = campaignFuture(1).map { campaign =>
    campaign.map(id => profileFuture(id.toInt))
  }

  // React on Futures which are done
  listOfProfileFuturesFuture foreach { campaignFutureRes =>
    campaignFutureRes.foreach { profileFutureRes =>
      profileFutureRes.foreach(profileListEntry => println(s"${new Date} done: $profileListEntry"))
    }
  }


  // !!ONLY FOR TESTING PURPOSE - THIS CODE BLOCKS AND EXITS THE VM WHEN THE FUTURES ARE DONE!!
  println(s"${new Date} waiting for futures")
  listOfProfileFuturesFuture.foreach{listOfFut =>
    Await.ready(Future.sequence(listOfFut), Duration.Inf)
    println(s"${new Date} all futures done")
    System.exit(0)
  }
  scala.io.StdIn.readLine()

すべての Future の結果を一度に取得するには

  import scala.concurrent.{Future, Await}
  import scala.concurrent.duration.Duration
  import scala.concurrent.ExecutionContext.Implicits.global

  def campaignFuture(advertiserId: Int): Future[List[BigInt]] = Future {
    List(1, 2, 3)
  }
  def profileFuture(profileId: Int): Future[List[String]] = Future {
    List(s"profile-for:$profileId")
  }


  // type: Future[List[Future[List[String]]]]
  val listOfProfileFutures = campaignFuture(1).map { campaign =>
    campaign.map(id => profileFuture(id.toInt))
  }

  // type: Future[List[List[String]]]
  val listOfProfileFuture = listOfProfileFutures.flatMap(s => Future.sequence(s))


  // print the result
  //listOfProfileFuture.foreach(println)
  //scala.io.StdIn.readLine()

  // wait for the result (THIS BLOCKS INFINITY!)
  Await.result(listOfProfileFuture, Duration.Inf)

  • Future.sequenceを使用して List[Future[T]] を Future[List[T]] に変換します。
  • Future[Future[T]] から Future[T] を取得するflatMap
  • 結果を待つ必要がある場合 (BLOCKING!)、Awaitを使用して結果を待ちます。
于 2014-11-12T07:24:00.907 に答える