coroutine"而“线程”呢?

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

97580 次浏览

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

通常,协程实现自愿让步,程序员决定yield的位置,即将控制权交给另一个例程。

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

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

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

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

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

第一次读到: 并发和并行——有什么区别?

并发性是将分离的任务提供交错 执行。并行是同时执行多个任务 为了提高工作速度。-https://github.com/servo/servo/wiki/Design < / p >

简短的回答:使用线程,操作系统根据其调度器(操作系统内核中的一种算法)预先切换正在运行的线程。对于协程,程序员和编程语言决定何时切换协程;换句话说,通过在设置点暂停和恢复函数,任务是协作多任务的,通常(但不一定)在单个线程中。

长一点的回答:与线程相反,线程是由操作系统预先调度的,协程开关是合作的,这意味着程序员(可能还有编程语言及其运行时)控制开关何时发生。

与线程相比,协程开关是抢占式的 合作(程序员控制切换发生的时间)。的 内核不涉及协同程序开关。 -http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html < / p >

支持原生线程的语言可以将其线程(用户线程)执行到操作系统的线程(内核线程)上。每个进程至少有一个内核线程。内核线程就像进程一样,只是它们在自己的进程中与该进程中的所有其他线程共享内存空间。一个进程“拥有”它所分配的所有资源,如内存、文件句柄、套接字、设备句柄等,这些资源都在它的内核线程之间共享。

操作系统调度器是内核的一部分,它在一定时间内(在单处理器机器上)运行每个线程。调度器为每个线程分配时间(时间切片),如果线程没有在该时间内完成,调度器将抢占它(中断它并切换到另一个线程)。多个线程可以在多处理器机器上并行运行,因为每个线程可以(但不一定必须)调度到单独的处理器上。

在单处理器机器上,线程被快速地进行时间切片和抢占(在Linux上,默认的时间切片是100ms),从而使它们成为并发的。然而,它们不能并行(同时)运行,因为单核处理器一次只能运行一个程序。

协同程序和/或发电机可以用来实现协作函数。它们不是在内核线程上运行并由操作系统调度,而是在单个线程中运行,直到它们屈服或结束,屈服于程序员决定的其他函数。带有发电机的语言,如Python和ECMAScript 6,可以用来构建协程。Async/await(见于c#, Python, ECMAscript 7, Rust)是建立在生成未来/承诺的生成器函数之上的抽象。

在某些情况下,协同程序可能指的是堆栈函数,而发电机可能指的是无堆栈函数。

纤维轻量级的线程绿色线程是协程或类似协程的其他名称。它们有时看起来(通常是故意的)更像编程语言中的操作系统线程,但它们不像真正的线程那样并行运行,而是像协程那样工作。(根据语言或实现的不同,这些概念之间可能有更具体的技术特殊性或差异。)

例如,Java有"绿色线程";这些线程是由Java虚拟机(JVM)调度的,而不是在底层操作系统的内核线程上本机调度的。它们不能并行运行,也不能利用多个处理器/核——因为那样需要一个本机线程!因为它们不是由操作系统调度的,所以它们更像协程而不是内核线程。在Java 1.2中引入本机线程之前,Java使用的是绿色线程。

线程消耗资源。在JVM中,每个线程都有自己的堆栈,通常大小为1MB。64k是JVM中每个线程允许的最小堆栈空间量。线程堆栈大小可以在JVM的命令行上配置。尽管名字如此,但线程并不是自由的,因为它们需要使用资源,比如每个线程都需要自己的堆栈、线程本地存储(如果有的话),以及线程调度/上下文切换/CPU缓存失效的成本。这就是为什么协同例程在性能关键、高度并发的应用程序中变得流行的部分原因。

Mac OS只允许一个进程分配大约2000个线程,Linux为每个线程分配8MB的堆栈,并且只允许物理RAM中可以容纳的线程数量。

因此,线程的权重最重(就内存使用和上下文切换时间而言),然后是协程,最后是生成器的权重最轻。

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

首先,如果协程运行同时(从不在平行中),为什么有人更喜欢它们而不是线程?

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

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

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

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

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

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

最后,协程受到了很多关注,因为在一些编程语言(如Python)中,你的线程无论如何都不能并行运行 -它们像协程一样并发运行,但没有低内存和自由调度开销。

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

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

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

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

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

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