j3d*_*j3d 6 scala future for-comprehension
鉴于以下方法......
def doSomething1: Future[Int] = { ... }
def doSomething2: Future[Int] = { ... }
def doSomething3: Future[Int] = { ... }
Run Code Online (Sandbox Code Playgroud)
......以及以下的理解:
for {
x <- doSomething1
y <- doSomething2
z <- doSomething3
} yield x + y + z
Run Code Online (Sandbox Code Playgroud)
这三种方法并行运行,但在我的情况下doSomething2必须在doSomething1完成之后运行.如何按顺序运行这三种方法?
编辑
正如Philosophus42所建议的,下面是一个可能的实现doSomething1:
def doSomething1: Future[Int] = {
// query the database for customers younger than 40;
// `find` returns a `Future` containing the number of matches
customerService.find(Json.obj("age" -> Json.obj("$lt" -> 40)))
}
Run Code Online (Sandbox Code Playgroud)
...所以它Future是由对另一个方法的内部调用创建的.
编辑2
也许我过分简化了用例......我很抱歉.让我们再试一次,更接近真实的用例.以下是三种方法:
for {
// get all the transactions generated by the exchange service
transactions <- exchange.orderTransactions(orderId)
//for each transaction create a log
logs <- Future.sequence(tansactions.map { transaction =>
for {
// update trading order status
_ <- orderService.findAndUpdate(transaction.orderId, "Executed")
// create new log
log <- logService.insert(Log(
transactionId => transaction.id,
orderId => transaction.orderId,
...
))
} yield log
})
} yield logs
Run Code Online (Sandbox Code Playgroud)
我要做的是为与订单关联的每个事务创建一个日志.logService.insert即使transactions只包含一个条目,也会被多次调用.
首先,里面的代码如何doSomethingX?更令人讨厌的是,使用您给定的代码,期货并行运行.
为了使Future执行顺序,只需使用
for {
v1 <- Future { ..block1... }
v2 <- Future { ..block2... }
} yield combine(v1, v2)
Run Code Online (Sandbox Code Playgroud)
这个工作的原因是,语句Future {..body ..}启动异步计算,在那个时间点评估语句.
随着上面的理解,desugared
Future { ..block1.. }
.flatMap( v1 =>
Future { ..block>.. }
.map( v2 => combine(v1,v2) )
)
Run Code Online (Sandbox Code Playgroud)
很明显,那
Future{ ...block1... }有结果,flatMap方法被触发,其中Future { ...block2... }.因此Future { ...block2... }在执行之后执行 Future { ...block1... }
一个 Future
Future {
<block>
}
Run Code Online (Sandbox Code Playgroud)
通过直接触发包含块的执行ExecutionContext
小片1:
val f1 = Future { <body> }
val f2 = Future { <otherbody> }
Run Code Online (Sandbox Code Playgroud)
这两个计算是并行运行的(如果你ExecutionContext这样设置的话),因为这两个值是立即计算的.
摘录2:
构造
def f1 = Future { ..... }
Run Code Online (Sandbox Code Playgroud)
一旦f1被召唤,将开始执行未来
编辑:
j3d,我仍然感到困惑,为什么你的代码没有按预期工作,如果你的语句是正确的,那么Future 是在computeSomethingX方法中创建的.
这是一个证明的代码片段,computeSomething2后面执行computeSomething1
import scala.concurrent.{Await,Future} import scala.concurrent.duration._
object Playground {
import scala.concurrent.ExecutionContext.Implicits.global
def computeSomething1 : Future[Int] = {
Future {
for (i <- 1 to 10) {
println("computeSomething1")
Thread.sleep(500)
}
10
}
}
def computeSomething2 : Future[String] = {
Future {
for(i <- 1 to 10) {
println("computeSomething2")
Thread.sleep(800)
}
"hello"
}
}
def main(args: Array[String]) : Unit = {
val resultFuture: Future[String] = for {
v1 <- computeSomething1
v2 <- computeSomething2
} yield v2 + v1.toString
// evil "wait" for result
val result = Await.result(resultFuture, Duration.Inf)
println( s"Result: ${result}")
}
}
Run Code Online (Sandbox Code Playgroud)
与输出
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething1
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
computeSomething2
Result: hello10
Run Code Online (Sandbox Code Playgroud)
编辑2
如果您希望它们并行执行,请事先创建期货(此处f1和f2)
def main(args: Array[String]) : Unit = {
val f1 = computeSomething1
val f2 = computeSomething2
val resultFuture: Future[String] = for {
v1 <- f1
v2 <- f2
} yield v2 + v1.toString
// evil "wait" for result
val result = Await.result(resultFuture, Duration.Inf)
println( s"Result: ${result}")
}
Run Code Online (Sandbox Code Playgroud)