“协程”和“线程”之间的区别?

“协同程序”和“线程”之间有什么区别?


协程是顺序处理的一种形式:在任何给定的时间只有一个正在执行(就像子程序AKA程序AKA的功能 - 它们只是更加流畅地将接力棒传递给彼此)。

线程(至少在概念上)是并发处理的一种形式:多个线程可以在任何给定的时间执行。 (传统上,在单CPU,单核机器上,并发性在OS的一些帮助下被模拟 - 现在,由于如此多的机器是多CPU和/或多核,线程事实上将同时执行,不只是“概念上”)。


首先阅读:并发VS并行 - 有什么区别?

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

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

长时间的回答:与线程相比,操作系统预先安排线程,协程开关是协作的,这意味着程序员(可能还有编程语言及其运行时)控制何时会发生切换。

与先发制人的线程相比,协同开关是协作的(程序员控制何时会发生切换)。 内核不参与协程开关。 -http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

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

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

在单个处理器机器上,线程被快速定时和抢占(在两者之间切换)(在Linux上,缺省时间片为100ms),这使得它们并发。 但是,它们不能并行(同时)运行,因为单核处理器一次只能运行一件事。

协程和/或生成器可用于实现协同功能。 它们不是在内核线程上运行并由操作系统调度,而是在单个线程中运行,直到它们产生或完成,由程序员确定其他函数。 带有生成器的语言(如Python和ECMAScript 6)可用于构建协程。 异步/等待(在C#中看到,Python,ECMAscript 7,Rust)是建立在产生期货/承诺的生成器函数之上的抽象。

在某些情况下, 协程可能会引用堆栈函数,而发生器可能会引用堆栈函数。

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

例如,Java有“ 绿色线程 ”; 这些是由Java虚拟机(JVM)调度的线程,而不是本地在底层操作系统的内核线程上调度的线程。 这些并不是并行运行或者利用多个处理器/内核 - 因为这需要本地线程! 由于它们不是由OS安排的,它们更像是协程而不是内核线程。 绿线程是Java直到本地线程被引入到Java 1.2之前所使用的线程。

线程消耗资源。 在JVM中,每个线程都有自己的堆栈,通常为1MB大小。 64k是JVM中每个线程允许的最小堆栈空间量。 线程堆栈大小可以在JVM的命令行上进行配置。 尽管有这个名称,线程并不是免费的,因为它们的使用资源(如每个线程需要自己的堆栈),线程本地存储(如果有)以及线程调度/上下文切换/ CPU高速缓存失效的代价。 这就是协程在性能关键,高度并发应用程序中流行的原因之一。

Mac OS只允许一个进程分配大约2000个线程,而Linux为每个线程分配8MB的堆栈,并且只允许多个线程适合物理RAM。

因此,线程是最重的(在内存使用和上下文切换时间方面),然后是协程,最后是发生器是最轻的重量。


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

首先,如果协同运行并行 (永远不会并行 ),为什么有人会喜欢它们而不是线程?

答案是,协程可以提供非常高的并发性水平,而且开销很小。 通常在一个线程环境中,最多有30-50个线程,然后实际上调度这些线程(通过系统调度程序)会大大减少线程真正有用的工作量。

对于线程来说,你可以有并行性,但并不是太多的并行性,是不是比单个线程中运行的协同程序更好呢? 不一定。 记住一个协同例程仍然可以在没有调度程序开销的情况下进行并发 - 它只是简单地管理自身的上下文切换。

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

由于很多例程都在做非常小的工作,并且彼此之间自动切换,所以您达到了调度程序无法实现的效率水平。 现在可以有数千个协同工作,而不是数十个线程。

因为您的例程现在可以相互切换预定点,所以现在您可以避免锁定共享数据结构(因为您永远不会告诉您的代码在关键部分中切换到另一个协程)

另一个好处是内存使用量要低得多。 使用线程模型时,每个线程都需要分配自己的堆栈,因此您的内存使用量随着线程数的增加而线性增长。 使用协同例程,您拥有的例程数与您的内存使用量没有直接关系。

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

链接地址: http://www.djcxy.com/p/13917.html

上一篇: Difference between a "coroutine" and a "thread"?

下一篇: threaded, then how does it do concurrent I/O?