我在Scala中有以下代码:
case class Water(temp: Int)
case class Milk(temp: Int)
def heatWaterFor(minutes: Int, water: Water) = Future {
Thread.sleep(1000)
Water(82)
}
def boilMilkFor(minutes: Int, milk: Milk) = Future {
Thread.sleep(1000)
Milk(90)
}
def frothMilk(hotwater: Water, hotmilk: Milk) = Future {
Thread.sleep(1000)
hotmilk
}
val start = System.currentTimeMillis()
val milkMaker = for {
water <- heatWaterFor(10, Water(10))
milk <- boilMilkFor(5, Milk(10))
frothed = frothMilk(water, milk)
hotMilk <- frothed
} yield (hotMilk)
Await.ready(milkMaker, Duration.Inf)
val end = System.currentTimeMillis() - start
println(milkMaker.value + " , Time taken: "+((end/1000))+" seconds.")
我的目的是并行化
heatWaterFor(...)
和boilMilkFor(...)
,因为它们是独立的。但是我觉得上面的代码是顺序的,根本没有利用期货的力量。显然,这需要3000毫秒才能运行(这是一个额外的证明)。我在这里想念的最根本的东西是什么?
最佳答案
for表达式可简化为一系列map
,flatMap
和withFilter
操作。您要表达的内容简化为以下形式:
heatWaterFor(10, Water(10))
.flatMap(water => boilMilkFor(5, Milk(10))
.flatMap(milk => frothMilk(water, milk))
如您在此处看到的,下一个future的执行在上一个完成时开始。因此,如果要并行执行它们,则需要执行以下操作:
val heatWater = heatWaterFor(10, Water(10))
val boilMilk = boilMilkFor(5, Milk(10))
val milkMaker = for {
water <- heatWater
milk <- boilMilk
hotMilk <- frothMilk(water, milk)
} yield (hotMilk)
这将同时启动
heatWaterFor
和boilMilkFor
,当这两个都完成时将启动frothMilk
(因为这取决于其他两个期货的结果)。