未来并行创建的by-name参数构建的未来

时间:2017-04-26 00:35:42

标签: scala

我正在尝试构建一个新的控制结构,为每个参数创建一个线程,并并行运行它们。当我为每个输入手动构建两个未来时,代码似乎没问题,因为我看到快速线程在慢速线程之前完成。

这是输出:

fast
slow

但是,如果我使用List(a, b).map(f => Future {f}),那么我总是看到快速线程在慢速完成后执行。这是输出:

slow
fast

有人可以解释一下吗?

代码粘贴在这里:

import java.util.concurrent.Executors

import scala.concurrent.{ExecutionContext, Future}

object ExecInParallel extends App {

  def run(a: => Unit, b: => Unit): Unit = {

    val executorService = Executors.newFixedThreadPool(2)
    implicit val executionContext = 
    ExecutionContext.fromExecutorService(executorService)

    // af and bf are executed in parallel
    val af = Future(a)
    val bf = Future(b)

    // however, the following code is not parallel
    List(a, b).map(f => Future(f))

    Thread.sleep(3000)
    executorService.shutdown
  }

  run(
    {
      Thread.sleep(2000)
      println("slow")
    }, 
    {
      Thread.sleep(1000)
      println("fast")
    }
  )
}

3 个答案:

答案 0 :(得分:1)

因为ab每次在非名称位置被引用时都会被评估,而List(a, b)参数不是按名称进行评估的。来自https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name

  

按名称调用是一种评估策略,其中函数的参数在调用函数之前不会被评估 - 而是......然后只要它们出现在函数中就会被评估。如果函数体中没有使用参数,则永远不会计算参数;如果多次使用,每次出现时都会重新评估。

实际上这相当于这段代码:

List({
  Thread.sleep(2000)
  println("slow")
  }, 
  {
    Thread.sleep(1000)
    println("fast")
  }).map(f => Future(f))

由于List构造函数不采用名称参数,因此在列表本身构造之前评估这些值

答案 1 :(得分:1)

这是因为您首先创建了两个调用名称值的列表:

List(a, b)...

并且直到 a b 未完全计算,才会执行映射操作。 当 List(a,b)准备就绪时,请将其包装在期货:

List(a, b).map(f => Future(f)) 

答案 2 :(得分:1)

b List(a, b)中构建Future之前,您的mapList(a, b)List[Unit]执行(按顺序)。如果您检查推断的List(a _, b _).map(f => Future(f())) 类型,则会看到它是<button>text inside<br />button</button>

要实现您的目标,您需要一个功能列表而不是结果列表。

以下内容可行:

{{1}}