2015-08-27 130 views
4

我在斯卡拉以下代码:斯卡拉期货基础知识

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毫秒(这是一个额外的证明)。

我在这里错过了什么基本的东西?

回答

1

我猜你正在关注:http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html。最后,它提到了为什么这段代码是顺序的,以及如何并行化它(最后一段代码片段)。

+0

你介意在这里发布相关代码吗?在SO中只有链接的答案是不被接受的。 – dcastro

+0

拿了点,但marstran已经在他的答案中发布了代码,所以我不会再发布它。 – markiz

1

检查this answer

总之,当你使用for这样,每个变量(watermilkfrothed)的开始时以前准备好评估。这允许在以后的评估中使用先前评估的结果,但它会使计算顺序化。

另外(无关)您创建期货的方法(heatWaterFor等)不使用参数。

3

表达式A被简化为一系列map,flatMapwithFilter操作。您的具体表达式可以简化为如下形式:

heatWaterFor(10, Water(10)) 
     .flatMap(water => boilMilkFor(5, Milk(10)) 
          .flatMap(milk => frothMilk(water, milk)) 

正如您在此处看到的,在前一个完成时开始执行下一个未来。因此,如果要执行他们都在并行,你需要做这样的事情:

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和同时,再启动frothMilk时,这两个完成(因为它依赖对另外两个期货的结果)。