线程和纤程有什么区别?

225

线程和纤程有什么区别?我从Ruby中听说过纤程,并且我也听说其他语言中也有纤程的存在,请有人简单地解释一下线程和纤程之间的区别。

线程是操作系统调度的基本单位,它管理着程序执行的流程。纤程则是在用户空间实现协程的一种方式,它可以在单个线程内模拟多个执行流程。纤程在某些情况下比线程更加轻量级,因为它们不需要进行上下文切换和内核态和用户态之间的转换。
9个回答

198
在最简单的术语中,线程通常被认为是抢占式的(尽管这可能并不总是正确,取决于操作系统),而纤程被认为是轻量级的、合作式的线程。两者都是应用程序的独立执行路径。
使用线程:当前执行路径可能随时被中断或抢占(注意:这个陈述是一个概括,可能不总是真实的,取决于操作系统/线程包等)。这意味着对于线程,数据完整性是一个重大问题,因为一个线程可能在更新一块数据的中途停止,导致数据的完整性变得不好或不完整。这也意味着操作系统可以通过同时运行多个线程来利用多个CPU和CPU核心,而将数据访问保护留给开发人员。
使用纤程:只有当纤程放弃执行时,当前执行路径才会被中断(与上面相同的注释)。这意味着纤程始终在明确定义的位置开始和停止,因此数据完整性的问题就少得多了。此外,由于纤程经常在用户空间中管理,因此不需要进行昂贵的上下文切换和CPU状态更改,使得从一个纤程转换到另一个纤程非常高效。另一方面,由于没有两个纤程可以完全同时运行,单纯地使用纤程将无法利用多个CPU或多个CPU核心。

10
有没有办法使用多线程并行执行纤程? - Baradé
3
@Jason,当你说 “with fibers the current execution path is only interrupted when the fiber yields execution”和“fibers always start and stop in well-defined places so data integrity is much less of an issue”时,你的意思是在共享变量时,我们不需要使用“锁定机制”和volatile变量吗?或者你的意思是我们仍然需要做这些事情? - Pacerier
@Baradé 这是一个有趣的问题,你找到答案了吗? - Mayur
@Baradé 是的。这种技术被称为M:N线程/调度。每N个线程有M个纤维。 - pro-gramer
从上面的定义中可以看出,只要亲和力保持不变,并且任务不会在某个核心上被中断,那么并发纤维在不同的核心上运行是可能的,这样每个纤维访问的数据就不会处于一些不完整的状态...或者也许这将不再是一个纤维...?! - sol
那么,纤维就是完全毫无用处的了。如果它不能在多个核心上运行,那么创建或使用它就没有任何意义。 - ScienceDiscoverer

66

线程使用抢占式调度,而纤程使用合作式调度。

使用线程时,控制流可以在任何时刻被中断,并且另一个线程可以接管。使用多个处理器时,您可以同时运行多个线程(同时多线程或SMT)。因此,您必须非常小心地处理并发数据访问,并使用互斥体、信号量、条件变量等来保护数据。这通常很棘手。

使用纤程时,只有在您告诉它切换时,控制才会转移,通常是使用类似于yield()的函数调用。这使得并发数据访问更加容易,因为您不必担心数据结构或互斥体的原子性。只要您不进行切换,就不会面临被抢占并且有另一个纤程尝试读取或修改您正在处理的数据的危险。结果,如果您的纤程进入无限循环,没有其他纤程可以运行,因为您没有切换。

您还可以混合使用线程和纤程,这会导致两者都面临的问题。虽然不建议这样做,但如果小心操作,有时可能是正确的选择。


3
我认为无限循环只是需要修复的错误,线程只有在存在无限循环时才具有相对隐晦的优势。相关的非错误概念是当有一个长时间运行的进程需要用户取消时。在这种情况下,无论你使用线程还是纤程,长时间运行的进程都需要合作——仅仅杀死线程可能会让一些数据结构混乱不堪。因此,更好的方法是例如长时间运行的进程线程会定期检查是否已被中断。这与纤程周期性地进行让出并没有太大区别。 - Evgeni Sergeev
请勿对Jason Coco的回答或他在这个领域的明确知识表示不尊重。我点赞你的回答,因为我觉得它简洁明了,并遵循了“不要让我思考”的原则。第一句话描述了谁有权安排线程或纤程继续处理其指令集的差异,使这个答案与众不同。 - user1561783

48

首先,建议阅读进程和线程之间的区别,作为背景资料。

一旦您阅读了它,就很容易理解了。线程可以在内核中、用户空间中实现,也可以混合使用。纤程(Fibers)基本上是在用户空间实现的线程。

  • 通常称为线程的是在内核中实现的执行线程:即所谓的内核线程。内核线程的调度完全由内核处理,尽管内核线程可以自愿释放CPU而休眠。内核线程的优点在于它可以使用阻塞I/O并让内核担心调度。其主要缺点是线程切换相对较慢,因为它需要陷入内核。
  • 纤程是在用户空间中进行调度的用户空间线程,由一个或多个内核线程在单个进程下处理调度。这使得纤程切换非常快。如果将所有访问特定共享数据集的纤程分组到单个内核线程的上下文中,并由单个内核线程处理它们的调度,则可以消除同步问题,因为纤程将有效地串行运行,并且您完全控制它们的调度。将相关纤程分组到单个内核线程下很重要,因为它们正在运行的内核线程可能会被内核抢占。许多其他答案没有明确说明这一点。此外,如果在纤程中使用阻塞I/O,则包括所有属于该内核线程的纤程在内,整个内核线程都会阻塞。

在《现代操作系统》的第11.4节"Windows Vista中的进程和线程"中,Tanenbaum评论道:

虽然纤程是合作调度的,但如果有多个线程调度纤程,则需要进行大量的仔细同步,以确保纤程不会相互干扰。为了简化线程和纤程之间的交互,通常只需要创建与处理器数量相同的线程,并将线程关联到每个独立的一组处理器上运行。

可用处理器,甚至只有一个处理器。每个线程可以运行一组特定的纤维,建立了线程和纤维之间的一对多关系,简化了同步。即使如此,纤维仍然存在许多困难。大多数Win32库完全不知道纤维,试图将纤维用作线程的应用程序会遇到各种失败。内核没有纤维的知识,当纤维进入内核时,它正在执行的线程可能会阻塞,并且内核将在处理器上调度任意线程,使其无法运行其他纤维。出于这些原因,除非从其他系统移植需要纤维提供的功能代码,否则很少使用纤维。


5
这是最全面的答案。 - Bernard

48
在Win32中,Fiber是一种用户管理的线程。 Fiber具有自己的堆栈、指令指针等,但Fiber不由操作系统进行调度:您必须显式地调用SwitchToFiber。 相比之下,线程是由操作系统预先调度的。 因此,粗略地说,Fiber是一个在应用程序/运行时级别上管理而不是真正的操作系统线程的线程。
其结果是Fiber更便宜,并且应用程序对调度具有更多控制权。如果应用程序创建了许多并发任务和/或希望紧密优化它们的运行时间,则这可能很重要。例如,数据库服务器可能会选择使用Fiber而不是线程。
(可能存在同一术语的其他用法;如上所述,这是Win32定义。)

12
请注意,除了线程和纤程之外,Windows 7 还引入了 用户模式调度

用户模式调度(UMS)是应用程序可以使用的轻量级机制,用于调度其自己的线程。应用程序可以在用户模式下在 UMS 线程之间切换,而不涉及系统调度程序,并且如果 UMS 线程在内核中阻塞,则可以重新控制处理器。UMS 线程与纤程的区别在于,每个 UMS 线程都具有自己的线程上下文,而不是共享单个线程的线程上下文。在用户模式下切换线程的能力使 UMS 比线程池更有效,用于管理需要很少的系统调用且持续时间短的大量工作项。

有关线程、纤程和 UMS 的更多信息,请观看 Dave Probert:Windows 7 内部-用户模式调度程序(UMS)


8

线程通常依赖内核中断线程,以便它或另一个线程可以运行(更为人所知的是抢占式多任务处理),而纤程使用协作式多任务处理,其中纤程本身放弃其运行时间,以便其他纤程运行。

以下是一些比我更好地解释它的有用链接:


8

线程最初被创建作为轻量级进程。类似地,纤程是一种轻量级线程,简单地依赖于纤程本身相互调度,通过让出控制权来实现。

我猜下一步将是使用线程,在每次您想要执行指令时必须向它们发送信号(与我的5岁儿子类似 :-)。在旧日子里(甚至现在的某些嵌入式平台上),所有线程都是纤程,没有抢占并且您必须编写您的线程以使其表现良好。


7

线程由操作系统进行调度(抢占式)。操作系统可以随时停止或恢复线程,但是纤程(Fiber)更多地是自我管理(协作式),并相互让出执行权。也就是说,程序员控制纤程何时进行处理以及何时将处理切换到另一个纤程。


6
Win32纤程定义实际上是在Sun Microsystems建立的“绿色线程”定义。没有必要将纤程这个术语用于某种类型的线程,即在用户代码/线程库控制下在用户空间中执行的线程。
为了澄清这个论点,请看以下评论:
- 使用超线程技术,多核CPU可以接受多个线程并将它们分配到每个核心上。 - 超标量流水线CPU接受一个线程进行执行,并使用指令级并行性(ILP)来更快地运行线程。我们可以假设一个线程被分成平行的纤程,在平行流水线上运行。 - SMT CPU可以接受多个线程,并将它们分解成指令纤程以在多个流水线上并行执行,更有效地利用流水线。
我们应该假定进程由线程组成,线程应由纤程组成。基于这种逻辑,将纤程用于其他类型的线程是错误的。

这很有趣。 - JSON

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接