我可以澄清 Project Loom 吗?

May I have Project Loom Clarified?

Brian Goetz 让我对 Loom 项目感到兴奋,为了充分理解它,我需要对现状进行一些澄清。

我的理解如下:目前,为了真正的并行,我们需要每个cpu/core有一个线程; 1) 那么在 n 核机器上拥有 n+1 个线程有什么意义吗? Loom 项目将给我们带来几乎无限的 threads/fibres,依靠 jvm 在 JVM 内部的虚拟线程上执行任务。 2)那真的是平行的吗? 3)具体来说,这与上述场景“n 核机器上的 n+1 个线程”有何不同?

感谢您的宝贵时间。

is there then any point in having n+1 threads on an n-core machine?

首先,大多数现代 n-core 机器有 n*2 个硬件线程,因为每个核心有 2 个硬件线程。

有时生成比硬件线程更多的 OS 线程确实有意义。当一些 OS 线程正在等待某事时,就是这种情况。例如,在 Linux 上,直到几年前 io_uring 到来之前,都没有很好的方法来为本地磁盘上的文件实现异步 I/O。传统上,disk-heavy 应用程序生成的线程多于 CPU 内核,并且使用阻塞 I/O。

Will that be truly parallel?

取决于实施。不仅是语言运行时,还有标准库的 I/O 相关部分。例如,在 Windows 上,当使用 async/await(相当于 project loom,2016 年左右发布)在 C# 中执行磁盘或网络 I/O 时,这些任务是真正并行的,OS 内核和驱动程序确实同时在做更多的工作。 Linux async/await 上的 AFAIK 仅适用于套接字而非文件,对于异步文件 I/O 它在后台使用 OS 线程池。

How, specifically, will that differ from the aforementioned scenario "n+1 threads on an n-core machine "?

OS 线程更贵有几个原因。 (1) 它们需要本机堆栈,因此每个 OS 线程都消耗内存 (2) 内存很慢,处理器有缓存来补偿,在 OS 线程之间切换会增加 RAM 带宽,因为 thread-specific 数据在之后失效上下文切换 (3) OS 调度程序几十年来一直在改进,但它们仍然不是免费的。原因之一是 saving/restoring 线程状态 to/from 内存需要时间。

与切换 OS 线程相比,在 C# async/await 或 Java 的 Loom 中实现的 higher-level 协作多任务处理在切换上下文时导致的开销要少得多。至少在理论上,这应该可以改善 I/O 繁重应用程序的吞吐量和延迟。

虚拟线程允许并发(IO 绑定),而不是并行(CPU 绑定)。它们代表因果同时性,但不代表资源使用同时性。

事实上,如果两个虚拟线程处于 IO bound* 状态(例如等待来自 REST 调用的 return),则根本没有线程被使用。然而,在调用完成之前,普通线程的使用(如果不使用反应式或可完成的语义)将被阻止并且无法使用。

*某些情况除外(例如,使用 synchonize 与 ReentrackLock,在本机方法中发生的阻塞,以及可能的其他一些小区域)。