这是代码:

import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.concurrent.duration._


val is = 1 to 100 toList
def db = s"${Thread.currentThread}"
def f(i: Int) = Future { println(db) ; 2 * i }

val theFuture = Future.traverse(is)(f _)

Await.result(theFuture, 10.seconds)

我运行了很多次,结果是这样的:
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-1,5,main]
Thread[ForkJoinPool-1-worker-5,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-7,5,main]
Thread[ForkJoinPool-1-worker-3,5,main]

模式始终是“Thread[ForkJoinPool-1-worker-”${AnOddNumber}”,5,main]”。有没有人知道为什么 worker 的 ID 总是奇数而不是偶数?

最佳答案

您正在使用 ExecutionContext.Implicits.global 执行上下文。在幕后,它使用 ForkJoinPool 来处理工作线程。这个 ForkJoinPool 由 Scala 库开发人员 fork ,以便根据他们的需要对其进行修改。你可以找到它 here

查看名为 registerWorker 的函数。工作人员的名称是通过添加前缀(这是名为 workerNamePrefix 的变量,默认值为 "ForkJoinPool-${POOL_ID}-worker-" )和池索引来构建的,该索引始终计算为奇数 ( see line 1712 )。因此,无论如何,这个数字总是奇数。这是由于实现避免了扫描工作队列数组,而是将其视为 2 的幂哈希表(这需要奇数索引进行双哈希。您可以查看有关哈希表的一些不错的文档以找到更多信息关于它)。

因此,您只需要 1、3、5 和 7 作为 worker 编号,因为您可能拥有一台 4 核计算机。如果您希望它们在输出中显得更加分散,只需在工作中添加一些延迟,以保持其他工作人员也忙碌。像这样:

def f(i: Int) = Future { println(db); Thread.sleep(100); 2 * i }

希望有帮助!

10-07 21:27