简体   繁体   English

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

[英]Difference between a “coroutine” and a “thread”?

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

First read: Concurrency vs Parallelism - What is the difference?首先阅读: 并发与并行 - 有什么区别?

Concurrency is the separation of tasks to provide interleaved execution.并发是分离任务以提供交错执行。 Parallelism is the simultaneous execution of multiple pieces of work in order to increase speed.并行是同时执行多个工作以提高速度。 https://github.com/servo/servo/wiki/Design https://github.com/servo/servo/wiki/Design

Short answer: With threads, the operating system switches running threads preemptively according to its scheduler, which is an algorithm in the operating system kernel.简短回答:对于线程,操作系统根据其调度程序抢先切换正在运行的线程,调度程序是操作系统内核中的一种算法。 With coroutines, the programmer and programming language determine when to switch coroutines;使用协程,程序员和编程语言决定何时切换协程; in other words, tasks are cooperatively multitasked by pausing and resuming functions at set points, typically (but not necessarily) within a single thread.换句话说,通过在设定点暂停和恢复功能,通常(但不一定)在单个线程内,任务可以协作地进行多任务处理。

Long answer: In contrast to threads, which are pre-emptively scheduled by the operating system, coroutine switches are cooperative, meaning the programmer (and possibly the programming language and its runtime) controls when a switch will happen.长答案:与由操作系统预先调度的线程相比,协程切换是协作的,这意味着程序员(可能还有编程语言及其运行时)控制切换何时发生。

In contrast to threads, which are pre-emptive, coroutine switches are cooperative (programmer controls when a switch will happen).与先发制人的线程相反,协程切换是协作的(程序员控制切换何时发生)。 The kernel is not involved in the coroutine switches.内核不参与协程切换。 http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

A language that supports native threads can execute its threads (user threads) onto the operating system's threads ( kernel threads ).支持本机线程的语言可以在操作系统的线程(内核线程)上执行其线程(用户线程)。 Every process has at least one kernel thread.每个进程至少有一个内核线程。 Kernel threads are like processes, except that they share memory space in their owning process with all other threads in that process.内核线程类似于进程,除了它们与该进程中的所有其他线程共享其拥有进程中的内存空间。 A process "owns" all its assigned resources, like memory, file handles, sockets, device handles, etc., and these resources are all shared among its kernel threads.进程“拥有”所有分配给它的资源,如内存、文件句柄、套接字、设备句柄等,这些资源都在其内核线程之间共享。

The operating system scheduler is part of the kernel that runs each thread for a certain amount time (on a single processor machine).操作系统调度程序是内核的一部分,它运行每个线程一定的时间(在单处理器机器上)。 The scheduler allocates time (timeslicing) to each thread, and if the thread isn't finished within that time, the scheduler pre-empts it (interrupts it and switches to another thread).调度器为每个线程分配时间(时间片),如果线程在这段时间内没有完成,调度器会抢占它(中断它并切换到另一个线程)。 Multiple threads can run in parallel on a multi-processor machine, as each thread can be (but doesn't necessarily have to be) scheduled onto a separate processor.多个线程可以在多处理器机器上并行运行,因为每个线程都可以(但不一定必须)调度到单独的处理器上。

On a single processor machine, threads are timesliced and preempted (switched between) quickly (on Linux the default timeslice is 100ms) which makes them concurrent.在单处理器机器上,线程被时间分片并快速抢占(切换)(在 Linux 上默认时间片是 100 毫秒),这使得它们并发。 However, they can't be run in parallel (simultaneously), since a single-core processor can only run one thing at a time.但是,它们不能并行(同时)运行,因为单核处理器一次只能运行一件事。

Coroutines and/or generators can be used to implement cooperative functions.协程和/或生成器可用于实现协作功能。 Instead of being run on kernel threads and scheduled by the operating system, they run in a single thread until they yield or finish, yielding to other functions as determined by the programmer.它们不是在内核线程上运行并由操作系统调度,而是在单个线程中运行,直到它们让步或完成为止,让步给程序员确定的其他功能。 Languages with generators , such as Python and ECMAScript 6, can be used to build coroutines.带有生成器的语言,例如 Python 和 ECMAScript 6,可用于构建协程。 Async/await (seen in C#, Python, ECMAscript 7, Rust) is an abstraction built on top of generator functions that yield futures/promises. Async/await(见于 C#、Python、ECMAscript 7、Rust)是一种建立在生成器函数之上的抽象,生成器函数生成期货/承诺。

In some contexts, coroutines may refer to stackful functions while generators may refer to stackless functions.在某些情况下,协程可能指堆栈函数,而生成器可能指无堆栈函数。

Fibers , lightweight threads , and green threads are other names for coroutines or coroutine-like things.纤程轻量级线程绿色线程是协程或类似协程的事物的其他名称。 They may sometimes look (typically on purpose) more like operating system threads in the programming language, but they do not run in parallel like real threads and work instead like coroutines.它们有时看起来(通常是故意的)更像是编程语言中的操作系统线程,但它们不像真正的线程那样并行运行,而是像协程一样工作。 (There may be more specific technical particularities or differences among these concepts depending on the language or implementation.) (根据语言或实现的不同,这些概念之间可能存在更具体的技术特殊性或差异。)

For example, Java had " green threads ";例如,Java 有“绿色线程”; these were threads that were scheduled by the Java virtual machine (JVM) instead of natively on the underlying operating system's kernel threads.这些是由 Java 虚拟机 (JVM) 调度的线程,而不是在底层操作系统的内核线程上本地调度的。 These did not run in parallel or take advantage of multiple processors/cores--since that would require a native thread!这些没有并行运行或利用多个处理器/内核——因为这需要一个本机线程! Since they were not scheduled by the OS, they were more like coroutines than kernel threads.由于它们不是由操作系统调度的,因此它们更像是协程而不是内核线程。 Green threads are what Java used until native threads were introduced into Java 1.2.在 Java 1.2 中引入原生线程之前,Java 一直使用绿色线程。

Threads consume resources.线程消耗资源。 In the JVM, each thread has its own stack, typically 1MB in size.在 JVM 中,每个线程都有自己的堆栈,大小通常为 1MB。 64k is the least amount of stack space allowed per thread in the JVM. 64k 是 JVM 中每个线程允许的最小堆栈空间量。 The thread stack size can be configured on the command line for the JVM.可以在 JVM 的命令行上配置线程堆栈大小。 Despite the name, threads are not free, due to their use resources like each thread needing its own stack, thread-local storage (if any), and the cost of thread scheduling/context-switching/CPU cache invalidation.尽管名称如此,线程并不是免费的,因为它们使用资源,例如每个线程需要自己的堆栈、线程本地存储(如果有)以及线程调度/上下文切换/CPU 缓存失效的成本。 This is part of the reason why coroutines have become popular for performance critical, highly-concurrent applications.这就是协程在性能关键、高度并发的应用程序中变得流行的部分原因。

Mac OS will only allow a process to allocate about 2000 threads, and Linux allocates 8MB stack per thread and will only allow as many threads that will fit in physical RAM. Mac OS 将只允许一个进程分配大约 2000 个线程,而 Linux 为每个线程分配 8MB 堆栈,并且只允许尽可能多的线程适合物理 RAM。

Hence, threads are the heaviest weight (in terms of memory usage and context-switching time), then coroutines, and finally generators are the lightest weight.因此,线程是最重的(就内存使用和上下文切换时间而言),然后是协程,最后是生成器是最轻的。

Coroutines are a form of sequential processing: only one is executing at any given time (just like subroutines AKA procedures AKA functions -- they just pass the baton among each other more fluidly).协程是顺序处理的一种形式:在任何给定时间只有一个正在执行(就像子程序 AKA 过程 AKA 函数一样——它们只是更流畅地在彼此之间传递指挥棒)。

Threads are (at least conceptually) a form of concurrent processing: multiple threads may be executing at any given time.线程(至少在概念上)是并发处理的一种形式:多个线程可以在任何给定时间执行。 (Traditionally, on single-CPU, single-core machines, that concurrency was simulated with some help from the OS -- nowadays, since so many machines are multi-CPU and/or multi-core, threads will de facto be executing simultaneously, not just "conceptually"). (传统上,在单 CPU、单核机器上,并发性是在操作系统的帮助下模拟的——如今,由于如此多的机器是多 CPU 和/或多核的,线程实际上将同时执行,不仅仅是“概念上”)。

About 7 years late, but the answers here are missing some context on co-routines vs threads.大约晚了 7 年,但这里的答案缺少关于协程与线程的一些上下文。 Why are coroutines receiving so much attention lately, and when would I use them compared to threads ?为什么协程最近受到如此多的关注,与线程相比,我什么时候会使用它们?

First of all if coroutines run concurrently (never in parallel ), why would anyone prefer them over threads?首先,如果协程并发运行(从不并行),为什么有人更喜欢它们而不是线程?

The answer is that coroutines can provide a very high level of concurrency with very little overhead .答案是协程可以以很少的开销提供非常高的并发性 Generally in a threaded environment you have at most 30-50 threads before the amount of overhead wasted actually scheduling these threads (by the system scheduler) significantly cuts into the amount of time the threads actually do useful work.通常在线程环境中,在实际调度这些线程(由系统调度程序)所浪费的开销显着减少线程实际执行有用工作的时间之前,您最多有 30-50 个线程。

Ok so with threads you can have parallelism, but not too much parallelism, isn't that still better than a co-routine running in a single thread?好的,对于线程,您可以具有并行性,但不能有太多并行性,这不是比在单个线程中运行的协同程序更好吗? Well not necessarily.嗯不一定。 Remember a co-routine can still do concurrency without scheduler overhead - it simply manages the context-switching itself.请记住,协程仍然可以在没有调度程序开销的情况下进行并发——它只是管理上下文切换本身。

For example if you have a routine doing some work and it performs an operation you know will block for some time (ie a network request), with a co-routine you can immediately switch to another routine without the overhead of including the system scheduler in this decision - yes you the programmer must specify when co-routines can switch.例如,如果你有一个例程在做一些工作并且它执行一个你知道会阻塞一段时间的操作(即网络请求),使用协同例程,你可以立即切换到另一个例程,而无需将系统调度程序包含在这个决定 - 是的,程序员必须指定何时可以切换协程。

With a lot of routines doing very small bits of work and voluntarily switching between each other, you've reached a level of efficiency no scheduler could ever hope to achieve.由于许多例程只做很少的工作并自愿在彼此之间切换,您已经达到了调度程序无法实现的效率水平。 You can now have thousands of coroutines working together as opposed to tens of threads.您现在可以让数千个协程协同工作,而不是数十个线程。

Because your routines now switch between each other a pre-determined points you can now also avoid locking on shared data structures (because you would never tell your code to switch to another coroutine in the middle of a critical section)因为你的例程现在在彼此之间切换一个预先确定的点,你现在还可以避免锁定共享数据结构(因为你永远不会告诉你的代码在临界区中间切换到另一个协程)

Another benefit is the much lower memory usage.另一个好处是内存使用量要低得多。 With the threaded-model, each thread needs to allocate its own stack, and so your memory usage grows linearly with the number of threads you have.使用线程模型,每个线程都需要分配自己的堆栈,因此您的内存使用量会随着您拥有的线程数线性增长。 With co-routines, the number of routines you have doesn't have a direct relationship with your memory usage.对于协同例程,您拥有的例程数量与您的内存使用没有直接关系。

And finally, co-routines are receiving a lot of attention because in some programming languages (such as Python) your threads cannot run in parallel anyway - they run concurrently just like coroutines, but without the low memory and free scheduling overhead.最后,协程受到了很多关注,因为在某些编程语言(例如 Python)中,您的线程无论如何都不能并行运行——它们就像协程一样并发运行,但没有低内存和免费调度开销。

In a word: preemption.一句话:抢占先机。 Coroutines act like jugglers that keep handing off to each other a well-rehearsed points.协程就像玩杂耍的人,不断地互相传递经过精心排练的分数。 Threads (true threads) can be interrupted at almost any point and then resumed later.线程(真正的线程)几乎可以在任何时候中断,然后再恢复。 Of course, this brings with it all sorts of resource conflict issues, hence Python's infamous GIL - Global Interpreter Lock.当然,这会带来各种资源冲突问题,因此 Python 臭名昭著的 GIL - Global Interpreter Lock。

Many thread implementations are actually more like coroutines.许多线程实现实际上更像是协程。

12 Years late to the discussion but a coroutine has the explaination in the name.讨论晚了 12 年,但协程在名称中有解释。 Coroutine can be decomposed into Co and Routine. Coroutine可以分解为Co和Routine。

A routine in this context is just a sequence of operations/actions and by executing / processing a routine the sequence of operations gets executed one by one in the exact same order as specified.在此上下文中的例程只是一系列操作/动作,并且通过执行/处理例程,操作序列将按照与指定的完全相同的顺序一个一个地执行。

Co stands for cooperation. Co代表合作。 A co routine is asked to (or better expected to) willingly suspend its execution to give other co-routines a chance to execute too.协程被要求(或更好地期望)自愿暂停其执行,以便给其他协程也有机会执行。 So a co-routine is about sharing CPU resources (willingly) so others can use the same resource as oneself is using.因此,协程是关于共享 CPU 资源(自愿),以便其他人可以使用自己正在使用的相同资源。

A thread on the other hand does not need to suspend its execution.另一方面,线程不需要挂起其执行。 Being suspended is completely transparent to the thread and the thread is forced by underlying hardware to suspend itself.被挂起对线程是完全透明的,并且线程被底层硬件强制挂起。 It is also done in a way so that it is mostly transparent to the thread as it does not get notified and it's state is not altered but saved and later restored when the thread is allowed to continue.它也以某种方式完成,以便它对线程几乎是透明的,因为它不会得到通知,并且它的状态不会改变,但会在允许线程继续时保存并稍后恢复。

One thing that is not true, that co-routines can not be concurrently executed and race conditions can not occur.有一件事是不正确的,即协程不能并发执行并且不会发生竞争条件。 It depends on the system that the co-routines are running on and it is easy possible to imaging co-routines .这取决于运行协程的系统,并且很容易对协程进行成像。

It does not matter how the co-routines suspend themselves.协程如何挂起自己并不重要。 Back in Windows 3.1 int 03 was woven into any programs (or had to be placed in there) and in C# we add yield.回到 Windows 3.1 int 03 被编入任何程序(或必须放在那里),而在 C# 中,我们添加了 yield。

It depends on the language you're using.这取决于您使用的语言。 For example in Lua they are the same thing (the variable type of a coroutine is called thread ).例如在 Lua 中它们是相同的(协程的变量类型称为thread )。

Usually though coroutines implement voluntary yielding where (you) the programmer decide where to yield , ie, give control to another routine.通常,虽然协程实现了自愿让步,但(您)程序员决定在哪里yield ,即,将控制权交给另一个例程。

Threads instead are automatically managed (stopped and started) by the OS, and they can even run at the same time on multicore CPUs.线程由操作系统自动管理(停止和启动),它们甚至可以在多核 CPU 上同时运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM