Scala 将异步调用与 Future 同步
Scala Synchronising Asynchronous calls with Future
我有一个方法可以查找几个数据库并执行一些逻辑。
我return从方法中得到的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)
每个 return 都是 Seq(Type1)
和 Seq(Type2)
条目的 Future
!
我现在的问题是从 Future
中取出 Seq(Type1)
和 Seq(Type2)
并将其填充到 MyResultType
案例中 class?
你可以参考你问的这个问题
所以你得到了
val results2: Future[Seq([Iterable[Type1], [Iterable[Type2])] = ???
然后在其上调用 await 并且你根本没有 Futures
,你可以做你想做的。
希望我理解正确。
哦,顺便说一句,你应该映射 myTypeOption
而不是检查它是否已定义并返回 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
}
如果我正确理解了你的问题,那么这应该可以解决问题。
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
}
}
您的问题分为两个部分,1) 如何处理两个相关的 future,以及 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()
/_.map()
对于大多数其他情况。
我有一个方法可以查找几个数据库并执行一些逻辑。
我return从方法中得到的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)
每个 return 都是 Seq(Type1)
和 Seq(Type2)
条目的 Future
!
我现在的问题是从 Future
中取出 Seq(Type1)
和 Seq(Type2)
并将其填充到 MyResultType
案例中 class?
你可以参考你问的这个问题
所以你得到了
val results2: Future[Seq([Iterable[Type1], [Iterable[Type2])] = ???
然后在其上调用 await 并且你根本没有 Futures
,你可以做你想做的。
希望我理解正确。
哦,顺便说一句,你应该映射 myTypeOption
而不是检查它是否已定义并返回 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
}
如果我正确理解了你的问题,那么这应该可以解决问题。
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
}
}
您的问题分为两个部分,1) 如何处理两个相关的 future,以及 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()
/_.map()
对于大多数其他情况。