线和纤维有什么区别?


187

线和光纤有什么区别?我听说过红宝石中的纤维,也听说过它们可以用其他语言提供,有人可以简单地向我解释一下线和纤维之间的区别是什么。

Answers:


162

用最简单的术语来说,线程通常被认为是抢占式的(尽管根据操作系统的不同,可能并不总是如此),而光纤则被认为是轻量级的协作线程。两者都是您的应用程序的单独执行路径。

带有线程:当前执行路径可以随时被中断或抢占(注意:该语句是一种概括,根据操作系统/线程包/等等,可能并不总是成立)。这意味着对于线程而言,数据完整性是一个大问题,因为一个线程可能在更新数据块的过程中停止,从而使数据完整性处于不良或不完整状态。这也意味着操作系统可以通过同时运行多个线程并将其留给开发人员来保护数据访问,从而利用多个CPU和CPU内核。

对于光纤:仅当光纤产生执行权时,才会中断当前执行路径(与上述相同)。这意味着光纤始终在定义明确的位置启动和停止,因此数据完整性不再是问题。另外,由于通常在用户空间中管理光纤,因此无需进行昂贵的上下文切换和CPU状态更改,从而使从一根光纤到另一根光纤的转换极为有效。另一方面,由于没有两个光纤可以完全同时运行,因此仅使用光纤将不会利用多个CPU或多个CPU内核。


7
有没有办法使用多个线程并行执行光纤?
Baradé

2
@Jason,当您声明“使用光纤时,当前执行路径仅在光纤产生执行时才会中断”和“光纤始终在定义明确的位置启动和停止,因此数据完整性不再是问题”,您的意思是共享变量时,我们不需要使用“锁定机制”和易失性变量吗?或者您是说我们仍然需要做这些事情?
Pacerier,2015年

@Baradé这是一个有趣的问题,您找到答案了吗?
Mayur

57

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

使用线程,控制流可以随时中断,而另一个线程可以接管。使用多个处理器,您可以使多个线程全部同时运行(同时多线程或SMT)。因此,您必须非常小心并发数据访问,并使用互斥量,信号量,条件变量等保护数据。正确通常很棘手。

对于光纤,只有在告诉您时,控制才会切换,通常是通过名为的函数调用yield()。这使并发数据访问更加容易,因为您不必担心数据结构或互斥锁的原子性。只要您不屈服,就不会有被抢占和让另一根光纤尝试读取或修改正在使用的数据的危险。但是,结果是,如果您的光纤陷入无限循环,则其他光纤将无法运行,因为您没有屈服。

您还可以混合使用线和纤维,这会引起两者都面临的问题。不建议这样做,但是如果仔细完成,有时可能是正确的选择。


3
我认为无限循环只是需要修复的错误,只有在存在无限循环时线程才具有相当模糊的优势。相关的非越野车概念是当用户可能希望取消长时间运行的过程时。在这种情况下,无论您使用线程还是纤维,长时间运行的进程都需要进行协作-杀死它的线程可能会使您的某些数据结构混乱,因此一种更好的方法是例如长时间运行的进程线程将定期检查如果它被打断了。这与定期产生纤维没有太大不同。
Evgeni Sergeev

43

在Win32中,光纤是一种用户管理的线程。光纤具有自己的堆栈和指令指针等,但是光纤不是由OS调度的:您必须显式调用SwitchToFiber。相比之下,线程是由操作系统抢先调度的。因此,大致来说,光纤是在应用程序/运行时级别管理的线程,而不是真正的OS线程。

结果是光纤价格便宜,并且应用程序可以更好地控制调度。如果应用程序创建了大量并发任务,并且/或者希望在运行时对其进行紧密优化,那么这可能很重要。例如,数据库服务器可能选择使用光纤而不是线程。

(同一术语可能还有其他用法;如上所述,这是Win32的定义。)


37

首先,我建议阅读有关进程和线程之间差异的解释作为背景材料。

阅读完后,这很简单。可以在内核,用户空间中实现线程,也可以将两者混合使用。光纤基本上是在用户空间中实现的线程。

  • 通常称为线程的是在内核中实现的执行线程:称为内核线程。尽管内核线程可以根据需要通过休眠自动释放CPU,但是内核线程的调度完全由内核处理。内核线程的优势在于它可以使用阻塞I / O并让内核担心调度。主要缺点是线程切换相对较慢,因为它需要捕获到内核中。
  • 光纤是用户空间线程,其调度是在一个进程中由一个或多个内核线程在用户空间中处理的。这使得光纤交换非常快。如果将所有访问一组特定光纤共享数据的光纤分组在单个内核线程的上下文中,并由单个内核线程处理它们的调度,则可以消除同步问题,因为光纤将有效地串行运行并且您已经完成了控制他们的日程安排。将相关的光纤分组在单个内核线程下非常重要,因为内核可以抢占它们正在运行的内核线程。在其他许多答案中,这一点并不清楚。另外,如果您在光纤中使用阻塞I / O,则整个内核线程都是块的一部分,包括属于该内核线​​程的所有光纤。

Tanenbaum在现代操作系统的11.4节“ Windows Vista中的进程和线程”中评论:

尽管对光纤进行了协同调度,但是如果有多个线程对光纤进行调度,则需要进行许多仔细的同步以确保光纤不会相互干扰。为了简化线程和光纤之间的交互,通常仅创建与要运行它们的处理器数量一样多的线程,并将每个线程仅在一组不同的可用处理器上运行,甚至仅在一个处理器上运行,这通常是有用的。每个线程然后可以运行光纤的特定子集,从而在线程和光纤之间建立一对多的关系,从而简化了同步。即使这样,纤维仍然存在许多困难。大多数Win32库完全不了解光纤,而试图将光纤当作线程使用的应用程序会遇到各种故障。内核不了解光纤,并且当光纤进入内核时,正在执行的线程可能会阻塞,内核将在处理器上调度任意线程,从而使其无法运行其他光纤。由于这些原因,除非从明显需要光纤提供功能的其他系统移植代码,否则很少使用光纤。


4
这是最完整的答案。
伯纳德

12

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

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

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


7

线程是由操作系统安排的(抢先式)。操作系统可以随时停止或恢复线程,但是光纤或多或少地自我管理(合作)并相互屈服。也就是说,程序员控制何时进行光纤处理以及何时该处理切换到另一根光纤。


7

线程通常依靠内核来中断线程,以便它或另一个线程可以运行(这被称为抢先式多任务处理),而光纤使用协作式多任务处理,而正是光纤本身放弃了它的运行时间,因此其他纤维可以运行。

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


7

线程最初是作为轻量级进程创建的。以类似的方式,纤维是轻质的线,通过屈服控制,(简单地)依靠纤维本身彼此调度。

我想下一步将是绞线,您每次要它们执行一条指令时都必须向它们发送信号(与我的5岁儿子:-一样)。在过去(甚至现在在某些嵌入式平台上),所有线程都是光纤,没有抢占,您必须编写线程才能表现良好。


3

Win32光纤定义实际上是Sun Microsystems建立的“ Green Thread”定义。无需将术语“光纤”浪费在某种类型的线程上,即在用户代码/线程库控制下在用户空间中执行的线程。

为了弄清楚参数,请看以下注释:

  • 借助超线程,多核CPU可以接受多个线程,并在每个内核上分配一个。
  • 超标量流水线CPU接受一个线程执行,并使用指令级并行(ILP)来更快地运行该线程。我们可以假设一个线程被分解为在并行管道中运行的并行光纤。
  • SMT CPU可以接受多个线程,并将它们制动为指令纤维,以便在多个管道上并行执行,从而更有效地使用管道。

我们应该假设进程是由线程组成的,线程应该由纤维组成。考虑到这种逻辑,将光纤用于其他种类的线程是错误的。


这是有趣的。
JSON
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.