ChatGPT解决这个技术问题 Extra ChatGPT

什么是“线程”(真的)?

我一直在尝试找到一个好的定义,并了解线程的真正含义。

似乎我肯定遗漏了一些明显的东西,但是每次我读到线程是什么时,它几乎都是一个循环定义,例如“线程是执行线程”或“划分为运行任务的方法”。呃呃。嗯?

从我所读到的内容看来,线程并不是真正的具体事物,就像进程一样。它实际上只是一个概念。根据我对这种工作方式的理解,处理器为程序执行一些命令(称为执行线程),然后当它需要切换到其他程序的处理时,它存储状态它当前正在某个地方(线程本地存储)执行的程序,然后开始执行其他程序的指令。来回。这样,线程实际上只是当前正在运行的程序的“执行路径之一”的概念。

与流程不同,流程确实是某种东西——它是资源的集合体,等等。

作为一个对我没有太大帮助的定义的例子。 . .

Wikipedia

“计算机科学中的线程是执行线程的缩写。线程是程序将自身划分(称为“拆分”)为两个或多个同时(或伪同时)运行的任务的一种方式。线程和进程不同于一个但一般来说,一个线程包含在一个进程中,同一个进程中的不同线程共享相同的资源,而同一个多任务操作系统中的不同进程则不共享。”

那我说得对吗?错误的?什么是真正的线程?

编辑:显然,一个线程也有自己的调用堆栈,所以这有点具体。

“过程”同样是一个抽象术语。
线程本地存储只是线程的调用堆栈吗?
下面的答案是……抽象的。用更简单的术语(并掩盖一些细节):曾几何时,计算机程序一次只能做一件事。所以它做了A,然后是B,然后是C,然后......在现代系统中,这并不理想。例如,您想在下载文件的同时继续浏览网页。所以程序现在有一个或多个“线程”。每个“线程”一次只能做一件事,但不同的线程可以同时做事。线程 1 可以做 A,然后是 B,然后是 C;线程 2 可以执行 X,然后是 Y,然后是 Z。在 A 完成之前,B 无法启动,但 A 和 X 可以同时发生。
@eric线程和进程之间的基本区别(实际上是最重要的区别)是两个或多个线程可以共享内存中的相同空间,即使用相同的资源,而两个进程必须存在于不同的内存空间中。那有意义吗?

p
pwnall

线程是一个执行上下文,它是 CPU 执行指令流所需的所有信息。

假设您正在阅读一本书,并且您现在想休息一下,但您希望能够回来并从您停止的确切位置继续阅读。实现这一目标的一种方法是记下页码、行号和字号。所以你阅读一本书的执行上下文就是这 3 个数字。

如果你有一个室友,并且她正在使用相同的技术,她可以在你不使用的时候拿走这本书,然后从她停下的地方继续阅读。然后你可以把它拿回来,从你原来的地方恢复它。

线程以相同的方式工作。 CPU 给您一种错觉,即它正在同时进行多个计算。它通过在每次计算上花费一些时间来做到这一点。它可以做到这一点,因为它对每个计算都有一个执行上下文。就像您可以与朋友分享一本书一样,许多任务可以共享一个 CPU。

在更技术层面上,执行上下文(因此是线程)由 CPU 寄存器的值组成。

最后:线程与进程不同。线程是执行的上下文,而进程是与计算相关联的一堆资源。一个进程可以有一个或多个线程。

澄清:与进程相关的资源包括内存页面(进程中的所有线程都拥有相同的内存视图)、文件描述符(例如,打开的套接字)和安全凭证(例如,启动进程的用户的 ID)过程)。


一个更好的类比是将人等同于 CPU(两者都做某事),并将书等同于地址空间(两者都存在)。这样,不同书籍中的书签就像不同进程中的线程。具有多个书签的单本书将类似于多线程进程,这就是人们通常所说的“线程”的意思。它适用于单处理器机器,但当您谈论多处理时,它会有点崩溃。没人关心哪个 CPU 执行函数 f(),但谁读第 11 章却很重要。
@pwnall,非常感谢您为像我这样的其他人消化了困难的概念!多线程是否涉及多处理(或在许多 CPU 上并行运行进程,以防我使用错误的术语)?
B
Ben Voigt

线程是处理器寄存器的一组独立值(对于单个内核)。由于这包括指令指针(又名程序计数器),它控制以什么顺序执行的内容。它还包括堆栈指针,它最好指向每个线程的唯一内存区域,否则它们会相互干扰。

线程是受控制流(函数调用、循环、goto)影响的软件单元,因为这些指令在指令指针上操作,并且属于特定线程。线程通常根据一些优先级方案进行调度(尽管可以设计一个每个处理器内核有一个线程的系统,在这种情况下每个线程都在运行,并且不需要调度)。

事实上,指令指针的值和存储在该位置的指令足以确定指令指针的新值。对于大多数指令,这只是将 IP 增加指令的大小,但控制流指令会以其他可预测的方式更改 IP。 IP 采用的值序列形成了一条贯穿程序代码的执行路径,从而产生了“线程”这个名称。


+1。线程并不比一组寄存器值更“具体”。
什么“价值观”?这些是什么?他们如何定义线程?
@Richard:CPU 寄存器的确切列表取决于架构,但指令指针和堆栈指针几乎是通用的。他们定义了一个线程,当这个线程(一组寄存器值)被加载到处理器内核中时,线程正在运行。处理器正在获取线程所需的指令并更新线程寄存器。当需要上下文切换时,处理器将这组寄存器值保存到内存中,并加载属于不同线程的一组值,通常作为中断服务逻辑的一部分。
谢谢本。这很有帮助。
嗨,谢谢@BenVoigt。像我这样的菜鸟可能会绊倒的一些澄清:“处理器寄存器”是什么意思? “指令指针”和“堆栈指针”是什么意思?
L
Leos313

为了正式定义线程,我们首先要了解线程运行的边界。

当计算机程序从某个存储加载到计算机内存中并开始执行时,它就变成了一个进程。一个进程可以由一个处理器或一组处理器执行。内存中的进程描述包含重要信息,例如跟踪程序中当前位置的程序计数器(即当前正在执行的指令)、寄存器、变量存储、文件句柄、信号等。

https://i.stack.imgur.com/BOMPb.png

线程位于同一进程地址空间内,因此,进程内存描述中存在的大部分信息可以跨线程共享。

某些信息无法复制,例如堆栈(每个线程指向不同内存区域的堆栈指针)、寄存器和特定于线程的数据。该信息足以允许线程独立于程序的主线程以及程序内的一个或多个其他线程进行调度。

运行多线程程序需要显式操作系统支持。幸运的是,大多数现代操作系统都支持线程,例如 Linux(通过 NPTL)、BSD 变体、Mac OS X、Windows、Solaris、AIX、HP-UX 等。操作系统可能使用不同的机制来实现多线程支持。

https://i.stack.imgur.com/Wc7oO.png

Here,您可以找到有关该主题的更多信息。那也是我的信息来源。

让我添加一个来自 Edward LeeSeshia 的来自 Introduction to Embedded System 的句子:

线程是并发运行并共享内存空间的命令式程序。他们可以访问彼此的变量。该领域的许多从业者更狭义地使用术语“线程”来指代构建共享内存的程序的特定方式,[其他]广义地指代命令式程序并发运行并共享内存的任何机制。在这个广义上,线程在几乎所有微处理器上都以中断的形式存在,即使根本没有任何操作系统(裸机)。


谢谢,这很有意义。
J
Joey Adams

流程就像两个人使用两台不同的计算机,必要时使用网络共享数据。线程就像使用同一台计算机的两个人,他们不必明确共享数据,但必须小心轮流。

从概念上讲,线程只是在同一地址空间中嗡嗡作响的多个工蜂。每个线程都有自己的堆栈、自己的程序计数器等,但进程中的所有线程共享相同的内存。想象一下两个程序同时运行,但它们都可以访问相同的对象。

将此与流程进行对比。每个进程都有自己的地址空间,这意味着一个进程中的指针不能用于引用另一个进程中的对象(除非您使用共享内存)。

我想要理解的关键是:

进程和线程都可以“同时运行”。

进程不共享内存(默认情况下),但线程与同一进程中的其他线程共享所有内存。

进程中的每个线程都有自己的堆栈和自己的指令指针。


您说“进程不共享任何内容(默认情况下)”,但在您的类比中,您说“进程就像两个人使用两台不同的计算机,他们在必要时使用网络共享数据”所以他们确实共享一些东西?
@committedandroider:好电话。我编辑了我的答案,说进程不共享内存(默认情况下),但线程共享所有内存。
c
chatuur

我将使用 ABRAHAM SILBERSCHATZ、PETER BAER GALVIN 和 GREG GAGNE 所著的《操作系统概念》一书中的大量文字以及我自己对事物的理解。

过程

任何应用程序都以文本(或代码)的形式驻留在计算机中。

我们强调程序本身并不是一个进程。程序是被动实体,例如包含存储在磁盘上的指令列表的文件(通常称为可执行文件)。

当我们启动一个应用程序时,我们会创建一个执行实例。这种执行实例称为进程。编辑:(根据我的解释,类似于一个类和一个类的实例,一个类的实例是一个过程。)

流程的一个例子是谷歌浏览器。当我们启动 Google Chrome 时,会产生 3 个进程:

• 浏览器进程负责管理用户界面以及磁盘和网络 I/O。 Chrome 启动时会创建一个新的浏览器进程。只创建一个浏览器进程。 • 呈现器进程包含用于呈现网页的逻辑。因此,它们包含处理 HTML、Javascript、图像等的逻辑。作为一般规则,为在新选项卡中打开的每个网站创建一个新的渲染器进程,因此多个渲染器进程可能同时处于活动状态。 • 为正在使用的每种类型的插件(例如 Flash 或 QuickTime)创建一个插件进程。插件进程包含插件的代码以及使插件能够与关联的渲染器进程和浏览器进程通信的附加代码。

线

要回答这个问题,我认为您应该首先了解处理器是什么。处理器是实际执行计算的硬件。编辑:(计算,如添加两个数字,对数组进行排序,基本上执行已编写的代码)

现在继续定义线程。

线程是CPU利用率的基本单位;它包括一个线程ID、一个程序计数器、一个寄存器集和一个堆栈。

编辑:来自英特尔网站的线程定义:

线程或执行线程是一个软件术语,表示可以通过单个 CPU 内核或由其处理的基本有序指令序列。

因此,如果来自 Chrome 应用程序的 Renderer 进程对数字数组进行排序,则排序将在执行的线程/线程上进行。 (关于线程的语法对我来说似乎很混乱)

我对事物的解释

流程是一个执行实例。线程是通过 CPU 访问执行计算的实际工作人员。当一个进程有多个线程运行时,该进程提供公共内存。

编辑:我发现对提供更多上下文有用的其他信息

所有现代计算机都有多个线程。计算机中的线程数取决于计算机中的内核数。

并发计算:

来自维基百科:

并发计算是一种计算形式,其中多个计算在重叠的时间段内同时执行,而不是顺序执行(一个在下一个开始之前完成)。这是系统的属性——可能是单个程序、计算机或网络——并且每个计算(“进程”)都有一个单独的执行点或“控制线程”。

因此,我可以编写一个程序来计算 4 个数字的总和:

(1 + 3) + (4 + 5)

在计算这个总和的程序中(这将是一个在执行线程上运行的进程),我可以派生另一个可以在不同线程上运行的进程来计算 (4 + 5) 并将结果返回给原始进程,而原始过程计算 (1 + 3) 的总和。


这是真正的交易答案
帮助很大。这就是解释的样子。
这个答案的一个重要价值在于它提供了一本参考书,如果需要,您可以在其中找到更多详细信息。谢谢@chatuur!
F
Flipper

这取自雅虎答案:

线程是不受应用程序架构影响的编码结构。单个进程通常可能包含多个线程。线程也可以直接相互通信,因为它们共享相同的变量。进程是具有自己状态信息的独立执行单元。它们也使用自己的地址空间,只能通过进程间通信机制与其他进程交互。

然而,简单地说,线程就像不同的“任务”。所以想想当你在做某事的时候,例如你在一张纸上写下一个公式。这可以被认为是一个线程。然后另一个线程是你在另一张纸上写别的东西。这就是多任务处理的用武之地。

据说英特尔处理器具有“超线程”(AMD 也有),它意味着能够更好地执行多个“线程”或多任务。

我不确定如何处理线程的逻辑。我确实记得听说过处理器在它们之间来回移动,但我对此不是 100% 确定,希望其他人可以回答这个问题。


英特尔处理器如何更好地处理多线程?对于单核,一次只能执行一个线程。我同意处理器来回走动。你真的不能做得更好吗?
这是一种优化,可为某些用例提供更好的性能。您可以在此处阅读有关超线程的信息:en.wikipedia.org/wiki/Hyper-threading
线程不像任务。任务是需要完成的工作单元。线程就像执行任务的代理。区别很重要,因为多线程程序中的一个常见比喻是,当需要执行某些任务时,哪个线程执行它并不重要。这个比喻最好通过线程池来体现,它是一个管理工作线程集合的对象。当一个任务对象被提交到一个线程池时,可以选择池中的任何一个工作线程来执行该任务。
R
Rad'Val

线程只不过是具有执行规则的内存上下文(或者 Tanenbaum 更好地把它称为资源分组)。这是一个软件结构。 CPU 不知道线程是什么(这里有些例外,有些处理器有硬件线程),它只是执行指令。

内核引入了线程和进程的概念,以一种有意义的方式管理内存和指令顺序。


B
Brandon Frohbieter

不幸的是,线程确实存在。线程是有形的东西。你可以杀死一个,而其他人仍然会运行。您可以生成新线程....虽然每个线程都不是它自己的进程,但它们在进程内单独运行。在多核机器上,可以同时运行 2 个线程。

http://en.wikipedia.org/wiki/Simultaneous_multithreading

http://www.intel.com/intelpress/samples/mcp_samplech01.pdf


是什么让它成为“有形的东西”?只是存储在 TLS 及其调用堆栈中的数据吗?
这不仅仅是理解的抽象......如果它真的只是一个伪装成多个线程来回运行的单个线程,那么 OP 是正确的,但是是的,我会说这些数据会使它变得有形.
开导我 。 . .所以答案是什么?
@Richard 不想进入关于语义的辩论,只是用我的回答来试图从概念上向 OP 澄清。
@richard 什么是 TLS?
h
hobbs

答案在不同的系统和不同的实现中差异很大,但最重要的部分是:

一个线程有一个独立的执行线程(即你可以从它上下文切换,然后返回,它会恢复运行它原来的位置)。一个线程有一个生命周期(它可以由另一个线程创建,另一个线程可以等待它完成)。它的包袱可能比“过程”少。

除此之外:线程可以通过语言运行时在单个进程中实现,线程可以是协程,线程可以通过线程库在单个进程中实现,或者线程可以是内核构造。

在几个现代 Unix 系统中,包括我最熟悉的 Linux,一切都是线程——进程只是线程的一种类型,它与其共享相对较少的东西父级(即它有自己的内存映射、自己的文件表和权限等) 阅读man 2 clone,尤其是标志列表,在这里真的很有启发性。


只是当处理器从一个线程转到另一个线程时(无论是在同一个进程中还是在另一个进程中),上下文切换吗?
v
vasilisdmr

线程是一组可以执行的(CPU)指令。

但是为了更好地理解线程是什么,需要一些计算机体系结构知识。

计算机所做的是遵循指令和操作数据。 RAM 是保存指令和数据的地方,处理器使用这些指令对保存的数据执行操作。

CPU 有一些称为寄存器的内部存储单元。它可以使用存储在这些寄存器中的数字执行简单的数学运算。它还可以在 RAM 和这些寄存器之间移动数据。这些是可以指示 CPU 执行的典型操作的示例:

将数据从内存位置#220 复制到寄存器#3

将寄存器#3 中的数字与寄存器#1 中的数字相加。

CPU 可以执行的所有操作的集合称为指令集。指令集中的每个操作都分配了一个编号。计算机代码本质上是代表 CPU 操作的数字序列。这些操作以数字形式存储在 RAM 中。我们将输入/输出数据、部分计算和计算机代码一起存储在 RAM 中。

CPU 在一个永无止境的循环中工作,总是从内存中获取并执行一条指令。这个周期的核心是 PC 寄存器或程序计数器。它是一个特殊寄存器,用于存储要执行的下一条指令的内存地址。

CPU 将:

取PC给定的内存地址处的指令,将PC加1,执行指令,返回步骤1。

可以指示 CPU 向 PC 写入新值,从而导致执行分支或“跳转”到内存中的其他位置。这种分支可以是有条件的。例如,一条 CPU 指令可以说:“如果寄存器 #1 等于 0,则将 PC 设置为地址 #200”。这允许计算机执行如下操作:

if  x = 0
    compute_this()
else
    compute_that()

Computer Science Distilled 使用的资源。


l
lambdakappatheta

正如进程代表虚拟计算机一样,线程抽象代表虚拟处理器。

所以线程是一种抽象。

抽象降低了复杂性。因此,第一个问题是线程解决了什么问题。第二个问题是如何实施。

至于第一个问题:线程使实现多任务更容易。这背后的主要思想是,如果每个任务都可以分配给唯一的工作人员,则不需要多任务处理。其实,暂时还可以把定义进一步概括,说线程抽象代表一个虚拟工作者。

现在,假设您有一个机器人,您想执行多项任务。不幸的是,它只能执行单个的、逐步的任务描述。好吧,如果你想让它成为多任务,你可以尝试通过交错你已经拥有的单独任务来创建一个大任务描述。这是一个好的开始,但问题是机器人坐在办公桌前,并在工作时将物品放在上面。为了把事情做好,你不能只是交错指令,还必须保存和恢复桌子上的项目。

这行得通,但现在很难通过简单地查看您创建的大任务描述来解开单独的任务。此外,保存和恢复标签上的项目的仪式很乏味,并且进一步混乱了任务描述。

这就是线程抽象的用武之地。它让你假设你有无数个机器人,每个机器人都坐在不同的房间里,坐在自己的办公桌前。现在,您可以将任务描述放入锅中,其他一切都由线程抽象的实现者处理。记住?如果有足够的工人,没有人必须同时处理多项任务。

通常,表明您的观点并说机器人表示真实机器人和虚拟机器人表示线程抽象为您提供的机器人很有用。

至此,对于任务完全独立的情况,多任务处理的问题得到了解决。然而,让机器人走出自己的房间,互动并朝着一个共同的目标一起工作不是很好吗?好吧,您可能已经猜到了,这需要协调。红绿灯,队列 - 你的名字。

作为中间总结,线程抽象解决了多任务处理的问题,并创造了合作的机会。没有它,我们只有一个机器人,所以合作是不可想象的。但是,它也给我们带来了协调(同步)的问题。现在我们知道胎面抽象解决了什么问题,而且,作为奖励,我们也知道它创造了什么样的新挑战。

但是等等,为什么我们首先关心多任务处理?

首先,如果任务涉及等待,多任务处理可以提高性能。例如,当洗衣机运转时,您可以轻松地开始准备晚餐。当你的晚餐结束时,你可以把衣服挂起来。请注意,您在这里等待,因为一个独立的组件会为您完成这项工作。涉及等待的任务称为 I/O bound 任务。

其次,如果多任务处理速度很快,从鸟瞰的角度来看,它看起来像是并行性。这有点像人眼如何将一系列静止图像快速连续显示为运动。如果我给爱丽丝写了一秒钟的信,给鲍勃也写了一秒钟,如果你只看我每两秒钟在做什么,你能分辨出我是同时写了两封信还是交替写了这封信?搜索多任务操作系统以了解更多信息。

现在,让我们关注如何实现线程抽象的问题。

本质上,实现线程抽象是关于编写一个任务,一个主任务,负责调度所有其他任务。

要问的一个基本问题是:如果调度器调度所有任务并且调度器也是一个任务,那么谁调度调度器?

让我们停下来。假设您编写了一个调度程序,编译它并将其加载到计算机的主存中,地址为 1024,该地址恰好是计算机启动时加载到处理器指令指针中的地址。现在,您的调度程序继续并在主内存中找到一些预编译的任务。例如,任务从地址 1,048,576 开始。调度程序想要执行这个任务,所以它将任务的地址(1,048,576)加载到指令指针中。嗯,这是一个考虑不周的举动,因为现在调度程序无法从它刚刚开始的任务中重新获得控制权。

一种解决方案是在执行之前将到调度程序(地址 1024)的跳转指令插入到任务描述中。实际上,您不应该忘记保存机器人正在工作的桌子上的物品,因此您还必须在跳跃之前保存处理器的寄存器。这里的问题是很难知道在哪里插入跳转指令。如果太多,它们会产生太多开销,如果它们太少,一项任务可能会垄断处理器。

第二种方法是要求任务作者指定几个可以将控制权转移回调度程序的地方。请注意,作者不必编写保存寄存器和插入跳转指令的逻辑,因为他们标记适当的位置就足够了,而调度程序负责其余的工作。这看起来是个好主意,因为任务作者可能知道,例如,他们的任务在加载并启动洗衣机后会等待一段时间,因此他们让调度程序在那里进行控制。

上述方法都没有解决的问题是错误或恶意任务,例如,陷入无限循环并且永远不会跳转到调度程序所在的地址。

现在,如果您无法在软件中解决问题怎么办?用硬件解决!所需要的是连接到处理器的可编程电路,其作用类似于闹钟。调度器设置一个定时器及其地址(1024),当定时器用完时,报警器保存寄存器并将指令指针设置为调度器所在的地址。这种方法称为抢占式调度。

可能现在您开始感觉到实现线程抽象不像实现链表。线程抽象最著名的实现者是操作系统。它们提供的线程有时称为内核级线程。由于操作系统不能承受失去控制,所有主要的通用操作系统都使用抢占式调度。

可以说,操作系统感觉是实现线程抽象的正确位置,因为它们控制所有硬件组件,并且可以非常明智地暂停和恢复线程。如果一个线程向操作系统请求存储在硬盘驱动器上的文件的内容,它会立即知道这个操作很可能需要一段时间,并且可以让另一个任务同时占用处理器。然后,一旦文件的内容可用,它可以暂停当前任务并恢复发出请求的任务。

然而,故事并没有到此结束,因为线程也可以在用户空间中实现。这些实现者通常是编译器。有趣的是,据我所知,内核级线程与线程所能获得的一样强大。那么为什么我们要为用户级线程而烦恼呢?原因当然是性能。用户级线程更轻量级,因此您可以创建更多线程,并且通常暂停和恢复它们的开销很小。

用户级线程可以使用 async/await 来实现。您还记得实现控制权返回调度程序的一种选择是让任务作者指定可以发生转换的位置吗?好吧,asyncawait 关键字正是为此目的。

现在,如果您已经做到了这一步,请做好准备,因为真正的乐趣来了!

您是否注意到我们几乎没有谈论并行性?我的意思是,我们不是使用线程来并行运行相关计算,从而提高吞吐量吗?好吧,不安静。实际上,如果您只想要并行性,则根本不需要这种机器。您只需创建与您拥有的处理单元数量一样多的任务,并且无需暂停或恢复任何任务。您甚至不需要调度程序,因为您不进行多任务处理。

从某种意义上说,并行性是一个实现细节。如果您考虑一下,线程抽象的实现者可以在后台使用任意数量的处理器。你可以从 1950 年开始编译一些编写良好的多线程代码,在今天的多核上运行它,看看它是否利用了所有内核。重要的是,编写该代码的程序员可能没有预料到该代码会在多核上运行。

您甚至可以争辩说,线程在用于实现并行性时被滥用:尽管人们知道他们不需要核心功能多任务处理,但他们使用线程来访问并行性。

作为最后的想法,请注意仅用户级线程无法提供并行性。还记得开头的那句话吗?操作系统在默认情况下通常配备单个虚拟处理器(线程)的虚拟计算机(进程)内运行程序。不管你在用户空间做了什么魔法,如果你的虚拟计算机只有一个虚拟处理器,你就不能并行运行代码。

那么我们想要什么?当然,我们需要并行性。但我们也想要轻量级线程。因此,许多线程抽象的实现者开始使用混合方法:他们启动与硬件中的处理单元一样多的内核级线程,并在几个内核级线程之上运行许多用户级线程。本质上,并行性由内核级处理,多任务处理由用户级线程处理。

现在,一个有趣的设计决策是语言公开的线程接口。例如,Go 提供了一个单一界面,允许用户创建混合线程,即所谓的 goroutines。在 Go 中,没有办法只要求一个内核级线程。其他语言对不同类型的线程有单独的接口。在 Rust 中,内核级线程存在于标准库中,而用户级和混合线程可以在 async-stdtokio 等外部库中找到。在 Python 中,asyncio 包提供用户级线程,而 multithreadingmultiprocessing 提供内核级线程。有趣的是,multithreading 提供的线程不能并行运行。另一方面,multiprocessing 提供的线程可以并行运行,但正如库的名称所暗示的那样,每个内核级线程都存在于不同的进程(虚拟机)中。这使得 multiprocessing 不适合某些任务,因为在不同虚拟机之间传输数据通常很慢。

更多资源:

Operating Systems: Principles and Practice by Thomas and Anderson

Concurrency is not parallelism by Rob Pike

Parallelism and concurrency need different tools

Asynchronous Programming in Rust

Inside Rust's Async Transform

Rust's Journey to Async/Await

What Color is Your Function?

Why goroutines instead of threads?

Why doesn't my program run faster with more CPUs?

John Reese - Thinking Outside the GIL with AsyncIO and Multiprocessing - PyCon 2018