我正在尝试构建一个新的控制结构,为每个参数创建一个线程,并并行运行它们。当我为每个输入手动构建两个未来时,代码似乎没问题,因为我看到快速线程在慢速线程之前完成。
这是输出:
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")
}
)
}
答案 0 :(得分:1)
因为a
和b
每次在非名称位置被引用时都会被评估,而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
之前,您的map
和List(a, b)
按List[Unit]
执行(按顺序)。如果您检查推断的List(a _, b _).map(f => Future(f()))
类型,则会看到它是<button>text inside<br />button</button>
。
要实现您的目标,您需要一个功能列表而不是结果列表。
以下内容可行:
{{1}}