Scala 我可以将Action.async与多个未来一起使用吗?
最后,我得到了关于在PlayFramework中使用Scala Futures的建议,谢谢。现在事情变得有点复杂了。比如说,在我绘制水果的地图之前:Scala 我可以将Action.async与多个未来一起使用吗?,scala,playframework,future,Scala,Playframework,Future,最后,我得到了关于在PlayFramework中使用Scala Futures的建议,谢谢。现在事情变得有点复杂了。比如说,在我绘制水果的地图之前: def getMapData(coll: MongoCollection[Document], s: String): Future[Seq[Document]] = ... def mapFruit(collection: MongoCollection[Document]) = Action.async { val fut = getMa
def getMapData(coll: MongoCollection[Document], s: String): Future[Seq[Document]] = ...
def mapFruit(collection: MongoCollection[Document]) = Action.async {
val fut = getMapData(collection, "fruit")
fut.map { docs: Seq[Document] =>
Ok(docs.toJson)
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
}
事实证明,人们更关心苹果而不是香蕉或樱桃,因此,如果地图上出现的物品不超过100件,人们希望苹果优先于香蕉和樱桃,但地图上出现的物品中苹果的比例不超过一定比例。某些函数pickDocs
确定正确的混合。我想这样的事情可能会管用,但不会:
def mapApplesBananasCherries(collection: MongoCollection[Document]) = Action.async {
val futA = getMapData(collection, "apples")
val futB = getMapData(collection, "bananas")
val futC = getMapData(collection, "cherries")
futA.map { docsA: Seq[Document] =>
futB.map { docsB: Seq[Document] =>
futC.map { docsC: Seq[Document] =>
val docsPicked = pickDocs(100, docsA, docsB, docsC)
Ok(docsPicked.toJson)
}
}
// won't compile without something here, e.g. Ok("whatever")
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
}
当我只有一个未来时,生活很简单,但现在我有三个未来。我该怎么做才能使它(1)起作用(2)再次变得简单?在这三种未来都有价值之前,我无法真正构建web响应。基本上,您应该使用flatMap
futA.flatMap { docsA: Seq[String] =>
futB.flatMap { docsB: Seq[String] =>
futC.map { docsC: Seq[String] =>
docsPicked = pickDocs(100, docsA, docsB, docsC)
Ok(docsPicked.toJson)
}
}
}
此外,您还可以使用以下内容进行理解:
val res = for {
docsA <- futA
docsB <- futB
docsC <- futC
} yield Ok(pickDocs(100, docsA, docsB, docsC).toJson)
res.recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
val res=for{
docsA基本上,你应该使用平面图
futA.flatMap { docsA: Seq[String] =>
futB.flatMap { docsB: Seq[String] =>
futC.map { docsC: Seq[String] =>
docsPicked = pickDocs(100, docsA, docsB, docsC)
Ok(docsPicked.toJson)
}
}
}
此外,您还可以使用以下内容进行理解:
val res = for {
docsA <- futA
docsB <- futB
docsC <- futC
} yield Ok(pickDocs(100, docsA, docsB, docsC).toJson)
res.recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
val res=for{
docsA这是期货和“包含价值”的类似类别的一种非常常见的模式(例如,选项
,列表
)
若要组合要使用的结果,请使用该方法和生成的代码
def mapApplesBananasCherries(collection: MongoCollection[Document]) = Action.async {
val futA = getMapData(collection, "apples")
val futB = getMapData(collection, "bananas")
val futC = getMapData(collection, "cherries")
futA.flatMap { docsA =>
futB.flatMap { docsB =>
futC.map { docsC =>
val docsPicked = pickDocs(100, docsA, docsB, docsC)
Ok(docsPicked.toJson)
}
}
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
}
事实上,它非常常见,存在一种特殊的语法来提高可读性,这需要理解:下面的代码相当于前面的代码片段
def mapApplesBananasCherries(collection: MongoCollection[Document]) = Action.async {
val futA = getMapData(collection, "apples")
val futB = getMapData(collection, "bananas")
val futC = getMapData(collection, "cherries")
for {
apples <- futA
bananas <- futB
cherries <- futC
} yield {
val docsPicked = pickDocs(100, apples, bananas, cherries)
Ok(docsPicked.toJson)
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
}
def mapapplesbanascherries(集合:MongoCollection[Document])=Action.async{
val futA=getMapData(收集,“苹果”)
val futB=getMapData(收集,“香蕉”)
val futC=getMapData(收集,“樱桃”)
为了{
苹果这是期货和“包含价值”的类似类别的一种非常常见的模式(例如选项
,列表
)
若要组合要使用的结果,请使用该方法和生成的代码
def mapApplesBananasCherries(collection: MongoCollection[Document]) = Action.async {
val futA = getMapData(collection, "apples")
val futB = getMapData(collection, "bananas")
val futC = getMapData(collection, "cherries")
futA.flatMap { docsA =>
futB.flatMap { docsB =>
futC.map { docsC =>
val docsPicked = pickDocs(100, docsA, docsB, docsC)
Ok(docsPicked.toJson)
}
}
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
}
事实上,它非常常见,存在一种特殊的语法来提高可读性,这需要理解:下面的代码相当于前面的代码片段
def mapApplesBananasCherries(collection: MongoCollection[Document]) = Action.async {
val futA = getMapData(collection, "apples")
val futB = getMapData(collection, "bananas")
val futC = getMapData(collection, "cherries")
for {
apples <- futA
bananas <- futB
cherries <- futC
} yield {
val docsPicked = pickDocs(100, apples, bananas, cherries)
Ok(docsPicked.toJson)
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
}
def mapapplesbanascherries(集合:MongoCollection[Document])=Action.async{
val futA=getMapData(收集,“苹果”)
val futB=getMapData(收集,“香蕉”)
val futC=getMapData(收集,“樱桃”)
为了{
苹果如果我的理解是您希望以该优先级执行苹果、樱桃和香蕉,那么我将对其进行类似的编码
import scala.concurrent.{Await, Future}
import scala.util.Random
import scala.concurrent.duration._
object WaitingFutures extends App {
implicit val ec = scala.concurrent.ExecutionContext.Implicits.global
val apples = Future {50 + Random.nextInt(100)}
val cherries = Future {50 + Random.nextInt(100)}
val bananas = Future {50 + Random.nextInt(100)}
val mix = for {
app <- apples
cher <- if (app < 100) cherries else Future {0}
ban <- if (app + cher < 100) bananas else Future {0}
} yield (app,cher,ban)
mix.onComplete {m =>
println(s"mix ${m.get}")
}
Await.result(mix, 3 seconds)
}
导入scala.concurrent.{wait,Future}
导入scala.util.Random
导入scala.concurrent.duration_
对象等待应用程序{
隐式val ec=scala.concurrent.ExecutionContext.Implicits.global
val apples=Future{50+Random.nextInt(100)}
val cherries=未来{50+随机.nextInt(100)}
val香蕉=未来{50+随机.nextInt(100)}
val mix=用于{
app如果我的理解是,您希望以该优先级执行苹果、樱桃和香蕉,那么我会编写类似于此的代码
import scala.concurrent.{Await, Future}
import scala.util.Random
import scala.concurrent.duration._
object WaitingFutures extends App {
implicit val ec = scala.concurrent.ExecutionContext.Implicits.global
val apples = Future {50 + Random.nextInt(100)}
val cherries = Future {50 + Random.nextInt(100)}
val bananas = Future {50 + Random.nextInt(100)}
val mix = for {
app <- apples
cher <- if (app < 100) cherries else Future {0}
ban <- if (app + cher < 100) bananas else Future {0}
} yield (app,cher,ban)
mix.onComplete {m =>
println(s"mix ${m.get}")
}
Await.result(mix, 3 seconds)
}
导入scala.concurrent.{wait,Future}
导入scala.util.Random
导入scala.concurrent.duration_
对象等待应用程序{
隐式val ec=scala.concurrent.ExecutionContext.Implicits.global
val apples=Future{50+Random.nextInt(100)}
val cherries=未来{50+随机.nextInt(100)}
val香蕉=未来{50+随机.nextInt(100)}
val mix=用于{
app这不会编译,因为嵌套的future块正在返回一个future[future[Response]]]
。如果改为在futures上使用flatMap
,您的futures将不会嵌套
如果您希望此操作的重复性稍低,可以使用Future.sequence
来同时启动期货。您可以使用模式匹配来重新提取列表:
val futureCollections = List("apples", "bananas", "cherries").map{ getMapData(collection, _) }
Future.sequence(futureCollections) map { case docsA :: docsB :: docsC :: Nil =>
Ok(pickDocs(100, docsA, docsB, docsC).toJson)
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
或者,您可以将一个列表列表(按优先级排序)交给pickDocs
函数,供其选择
Future.sequence(futureCollections) map { docLists =>
Ok(pickDocs(docLists, 100, 0.75f).toJson)
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
此pickDocs
实现将占列表头的一个百分比,除非完整列表中没有足够的文档(需要更多文档),然后递归地将相同的百分比应用于剩余的插槽列表
这不会编译,因为嵌套的future块正在返回一个future[future[Response]]]
。如果改为在futures上使用flatMap
,则不会嵌套futures
如果您希望此操作的重复性稍低,可以使用Future.sequence
来同时启动期货。您可以使用模式匹配来重新提取列表:
val futureCollections = List("apples", "bananas", "cherries").map{ getMapData(collection, _) }
Future.sequence(futureCollections) map { case docsA :: docsB :: docsC :: Nil =>
Ok(pickDocs(100, docsA, docsB, docsC).toJson)
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
或者,您可以将一个列表列表(按优先级排序)交给pickDocs
函数,供其选择
Future.sequence(futureCollections) map { docLists =>
Ok(pickDocs(docLists, 100, 0.75f).toJson)
} recover {
case e => Console.err.println("FAIL: " + e.getMessage); BadRequest("FAIL")
}
此pickDocs
实现将占列表头的一个百分比,除非完整列表中没有足够的文档(需要更多文档),然后递归地将相同的百分比应用于剩余的插槽列表
我认为他指的是并行化未来的计算,即使使用a来理解它也不会产生结果,直到futc完成val futA=getMapData(集合,“苹果”);val futB=getMapData(集合,“香蕉”);val futc=getMapData(集合,“樱桃”)
创造了这些未来,因此并行计算已经开始,理解只是对这些未来结果的平面图。谢谢你,伊戈尔,这非常清楚。谢谢路易斯和纳德!我认为他指的是并行化未来计算,即使使用理解,也不会产生,直到futc完成dval futA=getMapData(集合,“苹果”);val futB=getMapData(集合,“香蕉”);val futC=getMapData(集合,“樱桃”)
创建了这些未来,因此并行计算已经开始,为了理解这些未来的结果,只需要平面图。谢谢你,伊戈尔,这非常清楚。谢谢你,路易斯和纳德!不完全相同:在t