【问题标题】:What situations do single core threading beat threads across cores什么情况下单核线程击败跨核线程
【发布时间】:2022-01-18 09:49:22
【问题描述】:

我试图找到真实世界的示例,在这些示例中,在单核上运行线程可能比跨多核运行更有优势。

跨内核生成线程与在同一个内核中生成线程是否有成本。

java(或操作系统)如何确定何时在特定内核上分配工作。

最后,有没有办法明确指定线程应该在特定的核心上运行,或者这个操作系统级别是确定的?

【问题讨论】:

  • 您在第一句话中的意思是“多处理器”而不是“多进程”吗?这会改变你问题的含义,所以要准确。
  • 是更新到核心以明确表示 CPU 核心。不产生操作系统级别的进程,但具有相同的说法 java 进程产生在不同 cpu 内核上运行的线程
  • 您需要定义判断标题中“节拍”的标准。
  • 公平点,我主要是想了解多核执行是否有成本。我可以看到上下文切换 CPU 绑定任务的以下答案中提到的问题。但是对于线程主要在等待某些东西的非 CPU 绑定任务,是否跨内核执行此操作是否存在成本/收益。

标签: java multithreading operating-system multicore


【解决方案1】:

如果逻辑受 CPU 限制,则每个内核只需要一个线程,因为同一内核上的多个 CPU 绑定线程会由于上下文切换、冷缓存等而导致浪费。如果线程不受 CPU 限制,但我/O 绑定,每个内核使用多个线程可能是有益的。但这取决于架构,例如在 Seastar/Scylla 等每内核线程架构中,您仍然需要每内核一个线程。

Java 不做任何事情来确定线程如何映射到内核。这是操作系统的任务,因为 Java 线程与本机线程绑定。

在 Java 中,没有开箱即用的解决方案将线程固定到内核。但是您可以为此使用任务集或使用 Peter Lawrey 的库之一:

https://github.com/OpenHFT/Java-Thread-Affinity

【讨论】:

  • 谢谢,我以为是这样。但是我不明白的是,无论如何都不会发生上下文切换,因为操作系统将有自己的工作要做,即使将线程限制在 CPU 绑定任务的内核数量,操作系统仍会中断以完成它的事情
  • 更多的是非 CPU 绑定任务,例如生成 Web 请求和等待响应。这仍然会使多核受益,还是单核多线程没有成本?
  • 我只能说Linux。这取决于。操作系统的很多工作都是通过中断来处理的,例如当从网络接收到数据包时。并且如果有足够多的核心,而每个核心只有 1 个线程,那么上下文切换将非常少。
  • 在产生请求并等待响应的情况下:最终,单个 CPU 将成为瓶颈,您需要扩展到多个内核。多核有助于减少延迟,因为请求/响应的队列更少。
  • 是的,理解最终单个核心将成为多个请求的瓶颈。我主要是在问一个学术问题,说只有两个请求或任何不受 CPU 限制的线程基本上在等待的东西,在两个内核与一个内核中发生这种情况是否有任何成本?
【解决方案2】:

java(或操作系统)如何确定何时在特定内核上分配工作。

目前在基于 OpenJDK 的 Java 实现中,Java 线程与主机操作系统线程一对一映射。因此,每个平台(macOS、Linux、BSD、Windows、AIX 等)上的主机操作系统都会安排每个 Java 线程在它认为合适的内核上执行。

作为 Java 程序员,我们无法直接控制我们的 Java 线程何时安排执行时间。我们也不控制执行执行的核心。

有没有办法明确指定线程应该在特定的核心上运行

不,不是在 Java 中。

跨内核生成线程与在同一个内核中生成线程是否有成本。

我们不能将我们的 Java 线程限制在特定的内核上。所以你问题的第二部分没有意义。

至于生成线程的成本,是的,当前的 Java 成本很高。线程目前使用相当多的内存(堆栈分配)和 CPU 时间(Java 代码块时 CPU 内核可能处于空闲状态)。

Project Loom 旨在大大降低这一成本。他们努力的主旨是virtual threads,也称为纤维。 基于早期访问 Java 18 的 Project Loom 技术的实验版本现已推出。要了解更多信息,请观看 Ron Pressler 和 Alan Bateman 等 Loom 团队成员最近的演示和采访视频。

要了解有关 Java 线程的更多信息,请阅读 Brian Goetz 等人的这本优秀书籍:Java Concurrency In Practice。

【讨论】:

  • 对不起,我没有问产生线程是否有成本,无论它计划在哪里执行,都存在成本。我在问在不同的内核上执行两个线程是否有成本。明白我是 java ,这几乎是失控的,但从纯粹的学术角度来看,这样做有成本吗?
  • 我不确定 Java 线程是否会因为堆栈而消耗大量内存。在 Linux 上,您可以为某个地址范围分配内存,但它将使用共享零页进行初始化。所以如果线程stacksize为512*4096=2MB;可能实际上只需要分配前几页,因为它们被写入,其余的只是零页。我没有做过任何基准测试,所以我可能是错的。但如果 Java 线程急切地分配它们的堆栈,我会感到惊讶。
  • @pveebtjer 虚拟内存可以减轻一些负担,但最好避免。因为主机操作系统不知道 Java 代码的上下文,所以主机操作系统通常会分配一个相对较大的堆栈。即使使用虚拟内存,数百万个线程 * 2 MB 也可能存在问题。更重要的是,一旦使用堆栈内存通常不会放弃 - 堆栈不会收缩。 Project Loom 使用虚拟线程解决了这两个方面:(a)最初分配较小的堆栈,以及(b)在不再需要时缩小堆栈。请参阅 Project Loom 团队的 Ron Pressler 的演讲。
【解决方案3】:

单核线程在什么情况下优于跨核线程

如果有的话,非常少。简短的回答是,您应该相信 JVM 和操作系统在线程调度方面做正确的事情。

跨内核生成线程与在同一个内核中生成线程是否有成本。

当一个作业从一个处理器换出并且另一个作业代替它时,它的缓存内存[应该]无效是有代价的。在处理器之间来回切换会影响内存缓存速率和内存操作的性能,从而导致初始内存访问需要更长的时间。

java(或操作系统)如何确定何时在特定内核上分配工作。

它没有。它是操作系统上的本机线程库。

最后,有没有办法明确指定线程应该在特定的核心上运行,或者这个操作系统级别是确定的?

有一些本地调用可以控制特定内核的锁定作业。 我不确定是否要限制本机线程库。也就是说,我真的怀疑这是否值得。现在是 2021 年,现代操作系统在内核之间交换作业和有效管理它方面非常高效。您可以进行一大堆仅适用于您的特定操作系统(可能是特定操作系统版本)的本机调用,并且您可以轻松地使您的系统性能更差并占用更多资源。

【讨论】:

    猜你喜欢
    • 2019-02-20
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多