Java 线程和内核数

我刚刚有一个关于处理器和线程如何工作的简短问题。根据我目前的理解,一个核心一次只能执行1个过程。但是我们能够生成一个线程池(假设30),其数量大于我们拥有的内核数量(假设4),并让它们并发运行。如果我们只有4个核心,这怎么可能?我还能够在本地计算机上运行30线程程序,并继续在我的计算机上执行其他活动,例如看电影或浏览互联网。

我在某处读到过线程调度发生,这给人一种错觉,即这30个线程由4个内核并发运行。这是真的吗,如果是这样,有人可以解释它是如何工作的,并推荐一些好的阅读吗?

提前感谢您的帮助。


答案 1

进程与线程

在过去,每个进程只有一个执行线程,因此进程被直接调度到内核上(在过去,几乎只有一个内核可以调度)。但是,在支持线程的操作系统(几乎都是现代操作系统)中,调度的是线程,而不是进程。因此,在本讨论的其余部分,我们将专门讨论线程,您应该了解每个正在运行的进程都有一个或多个执行线程。

并行性与并发性

当两个线程并行运行时,它们都同时运行。例如,如果我们有两个线程,A和B,那么它们的并行执行将如下所示:

CPU 1:------------------------->

CPU 2: B ------------------------->

当两个线程同时运行时,它们的执行会重叠。重叠可以通过以下两种方式之一发生:线程同时执行(即并行执行,如上所述),或者它们的执行在处理器上交错,如下所示:

CPU 1:A -----------> B ----------> A -----------> B ---------->

因此,就我们的目的而言,并行性可以被视为并发的特例*

调度

但是我们能够生成一个线程池(假设30),其数量大于我们拥有的内核数量(假设4),并让它们并发运行。如果我们只有4个核心,这怎么可能?

在这种情况下,它们可以并发运行,因为 CPU 调度程序为这 30 个线程中的每一个线程提供了一些 CPU 时间份额。某些线程并行运行(如果您有 4 个内核,则任何时候都会有 4 个线程并行运行),但所有 30 个线程将同时运行。然后,您可以玩游戏或浏览网页的原因是这些新线程被添加到线程池/队列中,并且还获得了一部分CPU时间。

逻辑内核与物理内核

根据我目前的理解,一个核心一次只能执行1个过程。

并不完全正确。由于非常聪明的硬件设计和流水线,在这里要花很长时间(加上我不理解它),一个物理内核实际上有可能同时执行两个完全不同的执行线程。如果你需要的话,可以稍微咀嚼一下这句话——它仍然让我大吃一惊。

这个惊人的壮举被称为同步多线程(或流行的超线程,尽管这是此类技术的特定实例的专有名称)。因此,我们有物理内核,它们是实际的硬件CPU内核,还有逻辑内核,这是操作系统告诉软件可供使用的核心数量。逻辑内核本质上是一种抽象。在典型的现代英特尔 CPU 中,每个物理内核充当两个逻辑内核。

有人可以解释一下这是如何运作的,并推荐一些好的阅读吗?

如果您真的想了解进程,线程和调度如何协同工作,我会推荐操作系统概念

  • 术语并行并发的确切含义引起了激烈的争论,即使在我们自己的堆栈溢出中也是如此。这些术语的含义很大程度上取决于应用程序域。

答案 2

Java不执行线程调度,它将其保留在操作系统上以执行线程调度。

对于计算密集型任务,建议线程池大小等于可用内核数。但是对于 I/O 绑定任务,我们应该有更多数量的线程。如果两种类型的任务都可用并且需要 CPU 时间片,则还有许多其他变体。

一个内核一次只能执行 1 个进程

是的,但是他们可以同时处理多个任务并造成一种错觉,即他们一次处理多个进程

如果我们只有4个核心,这怎么可能?我还能够在本地计算机上运行30线程程序,并继续在我的计算机上执行其他活动

这是可能的,因为多任务处理(这是并发)。假设您启动了 30 个线程,操作系统也运行了 50 个线程,所有 80 个线程将通过逐个获取 CPU 时间片(一次每个内核一个线程)来共享 4 个 CPU 内核。这意味着平均每个内核将同时运行 80/4=20 个线程。你会感觉到所有的线程/进程同时运行。

有人可以解释一下这是如何工作的吗?

所有这些都发生在操作系统级别。如果你是一个程序员,那么你不应该担心这一点。但是,如果您是操作系统的学生,那么请选择任何一本操作系统书籍,并详细了解操作系统级别的多线程,或者找到一些好的研究论文以获得深度。您应该知道的一件事是,每个操作系统以不同的方式处理这些事情(但通常概念是相同的)

有一些语言,如Erlang,它们使用绿色线程(或进程),因此它们能够在自己的消除操作系统上映射和调度线程。因此,如果您有兴趣,也可以对绿色线程进行一些研究。

注意:您还可以研究Actor,这是对线程的另一种抽象。像Erlang,Scala等语言使用actor来完成任务。一个线程可以有数百个演员;每个Actor可以执行不同的任务(类似于java中的线程)。

这是一个非常广泛和活跃的研究课题,有很多东西需要学习。


推荐