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

问题描述 投票:148回答:5

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

architecture multithreading system coroutine
5个回答
108
投票

协程是一种顺序处理的形式:在给定的时间只有一个正在执行(就像子例程AKA过程AKA功能一样-它们只是使接力棒更流畅地相互传递)。

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


161
投票

首次阅读: Concurrency vs Parallelism - What is the difference?

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

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

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

与抢占式线程相反,协程开关是合作(程序员控制何时进行切换)。的协程开关不涉及内核。— http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

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

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

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

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

在某些情况下,协程可能是指堆栈函数,而生成器可能是指无堆栈函数。

纤维轻型线程绿色线程是协程或类似协程的事物的其他名称。它们有时看起来(通常是有目的的)更像是编程语言中的操作系统线程,但是它们并不像真正的线程那样并行运行,而是像协程一样运行。 (取决于语言或实现,这些概念之间可能会有更具体的技术特性或差异。)

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

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

Mac OS仅允许一个进程分配大约2000个线程,Linux为每个线程分配8MB堆栈,并且只允许将多个线程容纳在物理RAM中。

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


94
投票

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

首先,如果协程运行并发

(从不运行parallel,为什么有人会比线程更喜欢它们?

答案是协程可以提供非常高的并发性

非常少的开销。通常,在线程环境中,在(通过系统调度程序)实际调度这些线程的开销被浪费之前,您最多拥有30-50个线程,从而减少了线程实际做有用工作的时间。]好吧,对于线程,您可以具有并行性,但不能有太多的并行性,这还不比在单个线程中运行的协同例程还要好吗?那么不一定。请记住,协同例程仍可以在没有调度程序开销的情况下进行并发-它仅管理上下文切换本身。

例如,如果您有一个例程在做一些工作,并且它执行了您知道会阻塞一段时间的操作(即网络请求),那么使用协同例程,您可以立即切换到另一个例程,而不会增加系统的开销。这个决定中的调度程序-是的,程序员

必须指定何时可以切换协同例程。

通过许多例程完成很少的工作,并在彼此之间自愿切换,您已经达到了调度程序无法期望达到的效率水平。您现在可以将数千个协程协同工作,而不是数十个线程。

因为您的例程现在在彼此之间切换了预定点,所以您现在也可以

避免锁定

在共享数据结构上(因为您永远不会告诉您的代码在关键部分的中间切换到另一个协程) 另一个好处是内存使用率低得多。使用线程模型,每个线程都需要分配自己的堆栈,因此您的内存使用量会随着您拥有的线程数线性增长。对于协例程,您拥有的例程数量与内存使用没有直接关系。

最后,协同例程引起了很多关注,因为在某些编程语言(例如Python)中,您的

线程无论如何都不能并行运行

-它们像协程一样并发运行,但是没有低内存和空闲空间安排开销。
总而言之:抢占。协程就像杂耍演员一样,不断地互相传授经验教训。线程(真正的线程)几乎可以在任何时候中断,然后在以后恢复。当然,这带来了各种各样的资源冲突问题,因此,Python臭名昭著的GIL-全局解释器锁。

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

取决于您使用的语言。例如在Lua they are the same thing中(协程的变量类型称为thread)。

通常,协程会在(您)程序员决定yield的位置(即,将控制权交给另一个例程的地方实现自愿产生)。>>

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


18
投票
总而言之:抢占。协程就像杂耍演员一样,不断地互相传授经验教训。线程(真正的线程)几乎可以在任何时候中断,然后在以后恢复。当然,这带来了各种各样的资源冲突问题,因此,Python臭名昭著的GIL-全局解释器锁。

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


9
投票
取决于您使用的语言。例如在Lua they are the same thing中(协程的变量类型称为thread)。

通常,协程会在(您)程序员决定yield的位置(即,将控制权交给另一个例程的地方实现自愿产生)。>>

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


0
投票
协程仅表示单独的堆栈上下文。 “进程”或“线程”是协程循环列表的成员。系统时钟中断会定期触发,并且中断处理程序将上下文从当前协程交换到环上的下一个协程。
© www.soinside.com 2019 - 2024. All rights reserved.