Scala使用Future同步异步调用

时间:2015-09-28 13:14:03

标签: scala future

我有一个方法可以查找几个数据库并执行一些逻辑。

我从方法返回的MyType对象如下:

case class MyResultType(typeId: Long, type1: Seq[Type1], type2: Seq[Type2])

方法定义如下:

def myMethod(typeId: Long, timeInterval: Interval) = async {

  // 1. check if I can find an entity in the database for typeId  
  val myTypeOption = await(db.run(findMyTypeById(typeId))) // I'm getting the headOption on this result

  if (myTypeOption.isDefined) {

    val anotherDbLookUp = await(doSomeDBStuff) // Line A

    // the interval gets split and assume that I get a List of thse intervals
    val intervalList = splitInterval(interval)

    // for each of the interval in the intervalList, I do database look up
    val results: Seq[(Future[Seq[Type1], Future[Seq[Type2])] = for {
      interval <- intervalList
    } yield {
      (getType1Entries(interval), getType2Entries(interval))
    }
    // best way to work with the results so that I can return MyResultType 
  }
  else {
    None
  }
}

现在,getType1Entries(interval)getType2Entries(interval)每个都会返回FutureSeq(Type1)Seq(Type2)条目!

我现在的问题是从Seq(Type1)中取出Seq(Type2)Future并将其填入MyResultType案例类?

3 个答案:

答案 0 :(得分:2)

你可以参考你提出的这个问题

Scala transforming a Seq with Future

所以你得到了

val results2: Future[Seq([Iterable[Type1], [Iterable[Type2])] = ???

然后打电话等待它,你根本就没有Futures,你可以做你想做的事。

我希望我能正确理解这个问题。

哦,顺便说一句,你应该映射myTypeOption而不是检查它是否已定义,如果不是<{p}则返回None

if (myTypeOption.isDefined) {
  Some(x)
} else {
  None
}

可以简单地替换为

myTypeOption.map { _ => // ignoring what actually was inside option
  x                     // return whatever you want, without wrapping it in Some
}

答案 1 :(得分:0)

如果我理解你的问题,那么这应该可以解决问题。

def myMethod(typeId: Long, timeInterval: Interval): Option[Seq[MyResultType]] = async {

    // 1. check if I can find an entity in the database for typeId
    val myTypeOption = await(db.run(findMyTypeById(typeId))) // I'm getting the headOption on this result

    if (myTypeOption.isDefined) {

      // the interval gets split and assume that I get a List of thse intervals
      val intervalList = splitInterval(interval)

      // for each of the interval in the intervalList, I do database look up
      val results: Seq[(Future[Seq[Type1]], Future[Seq[Type2]])] = for {
        interval <- intervalList
      } yield {
          (getType1Entries(interval), getType2Entries(interval))
      }
      // best way to work with the results so that I can return MyResultType
      Some(
        await(
          Future.sequence(
            results.map{
              case (l, r) =>
                l.zip(r).map{
                  case (vl, vr) => MyResultType(typeId, vl, vr)
                }
            })))
    }
    else {
      None
    }
  }

答案 2 :(得分:0)

您的问题有两个部分,1)如何处理两个相关的未来,以及2)如何提取结果值。

在处理从属期货时,我通常会将它们组合在一起:

val future1 = Future { 10 }
val future2 = Future { 20 }

// results in a new future with type (Int, Int)
val combined = for {
  a <- future1
  b <- future2
} yield (a, b)

// then you can use foreach/map, Await, or onComplete to do
// something when your results are ready..
combined.foreach { ((a, b)) =>
  // do something with the result here
}

要提取结果,我通常使用Await如果我需要进行同步响应,如果我需要处理潜在的失败,请使用_.onComplete(),并使用_.foreach() / {{1对于大多数其他情况。