“协程”和“线程”有什么区别?


当前回答

12年后的讨论,但一个协程有解释的名字。协程可以分解为Co和Routine。

在这种情况下,例程只是一系列操作/动作,通过执行/处理例程,操作序列将按照指定的完全相同的顺序逐个执行。

Co代表合作。一个协同例程被要求(或者更好地期望)自愿暂停它的执行,以给其他协同例程一个执行的机会。因此,协程是关于共享CPU资源(自愿地),以便其他人可以使用自己正在使用的相同资源。

另一方面,线程不需要挂起它的执行。挂起对线程来说是完全透明的,底层硬件迫使线程自己挂起。它对线程来说是透明的,因为它不会被通知,它的状态不会被改变,而是被保存,然后在线程被允许继续时恢复。

有一件事是不正确的,协同例程不能并发执行,竞争条件不能发生。这取决于协同例程所运行的系统,对协同例程进行成像是很容易的。

协同例程如何悬挂自己并不重要。在Windows 3.1中,int 03被编织到任何程序中(或者必须放在那里),而在c#中,我们增加了yield。

其他回答

12年后的讨论,但一个协程有解释的名字。协程可以分解为Co和Routine。

在这种情况下,例程只是一系列操作/动作,通过执行/处理例程,操作序列将按照指定的完全相同的顺序逐个执行。

Co代表合作。一个协同例程被要求(或者更好地期望)自愿暂停它的执行,以给其他协同例程一个执行的机会。因此,协程是关于共享CPU资源(自愿地),以便其他人可以使用自己正在使用的相同资源。

另一方面,线程不需要挂起它的执行。挂起对线程来说是完全透明的,底层硬件迫使线程自己挂起。它对线程来说是透明的,因为它不会被通知,它的状态不会被改变,而是被保存,然后在线程被允许继续时恢复。

有一件事是不正确的,协同例程不能并发执行,竞争条件不能发生。这取决于协同例程所运行的系统,对协同例程进行成像是很容易的。

协同例程如何悬挂自己并不重要。在Windows 3.1中,int 03被编织到任何程序中(或者必须放在那里),而在c#中,我们增加了yield。

大约晚了7年,但是这里的答案缺少一些关于协同例程与线程的上下文。为什么协程最近受到如此多的关注,与线程相比,我什么时候会使用它们?

首先,如果协程是并发运行的(而不是并行运行的),为什么人们更喜欢协程而不是线程呢?

答案是协程可以用很少的开销提供非常高的并发性。通常在线程环境中,在实际调度这些线程所浪费的开销(由系统调度器)大大减少了线程实际执行有用工作的时间之前,您最多有30-50个线程。

好的,线程可以并行,但不能太多并行,这不是比在单个线程中运行协同例程更好吗?不一定。请记住,协同例程仍然可以在没有调度器开销的情况下实现并发—它只是管理上下文切换本身。

例如,如果你有一个例程在做一些工作,它执行一个你知道会阻塞一段时间的操作(即一个网络请求),有了协程,你可以立即切换到另一个例程,而不需要在这个决策中包括系统调度器的开销——是的,程序员必须指定协程何时可以切换。

通过大量的例程完成非常小的工作,并在彼此之间自动切换,您已经达到了任何调度器都无法企及的效率水平。您现在可以让数千个协程一起工作,而不是几十个线程。

因为你的例程现在可以在预先确定的点之间相互切换,你现在也可以避免锁定共享数据结构(因为你永远不会告诉你的代码在临界区中间切换到另一个协程)

另一个好处是更低的内存使用量。在线程模型中,每个线程都需要分配自己的堆栈,因此内存使用会随着线程数量的增加而线性增长。对于共同例程,你拥有的例程数量与你的内存使用量没有直接关系。

最后,协同例程受到了很多关注,因为在一些编程语言(如Python)中,线程不能并行运行——它们像协同例程一样并发运行,但没有低内存和免费的调度开销。

这取决于你使用的语言。例如,在Lua中,它们是一样的(协程的变量类型称为线程)。

通常,协程是由程序员自行决定在哪里让步,也就是说,把控制权交给另一个例程。

相反,线程由操作系统自动管理(停止和启动),它们甚至可以同时在多核cpu上运行。

协程是一种顺序处理的形式:在任何给定的时间只有一个在执行(就像子例程又名过程又名函数——它们只是更流畅地在彼此之间传递接力棒)。

线程(至少在概念上)是并发处理的一种形式:多个线程可以在任何给定时间执行。(传统上,在单cpu、单核机器上,并发性是在操作系统的帮助下模拟的——现在,由于很多机器都是多cpu和/或多核的,线程实际上是同时执行的,而不仅仅是“概念上”)。

一句话:抢占。协程就像杂耍演员一样,不断地互相传递精心排练过的分数。线程(真正的线程)几乎可以在任何时候中断,然后再恢复。当然,这也带来了各种资源冲突问题,因此才有了Python臭名昭著的GIL——全局解释器锁。

许多线程实现实际上更像协程。