Scala的"Future"的ForkJoinPool中,为什么一个worker的ID总是奇数?

In the ForkJoinPool for Scala's "Future", why is the ID for a worker always an odd number?

代码如下:

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]"。有没有人知道为什么工人的 ID 总是奇数而不是偶数?

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

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

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

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

希望对您有所帮助!