什么是协程?它们与并发性有什么关系?


当前回答

协程作为并发性的实现和多线程的替代方案。

协程是实现并发的单线程解决方案。

         A-Start ------------------------------------------ A-End   
           | B-Start -----------------------------------------|--- B-End   
           |    |      C-Start ------------------- C-End      |      |   
           |    |       |                           |         |      |
           V    V       V                           V         V      V      
1 thread->|<-A-|<--B---|<-C-|-A-|-C-|--A--|-B-|--C-->|---A---->|--B-->| 

与多线程解决方案相比:

thread A->|<--A|          |--A-->|
thread B------>|<--B|            |--B-->|
thread C ---------->|<---C|             |C--->|

协程是异步编程的一种实现,异步编程用于实现并发。 许多语言使用协程实现异步编程。其他答案表明Python, Kotlin, Lua, c++已经做到了。 最有用/通常用于涉及I/O绑定问题的场景,例如在获取数据时呈现UI,或从多个数据源下载。

其他回答

另一方面, 在python中,gevent库是一个基于协程的网络库,它为您提供线程类功能,如异步网络请求,而无需创建和销毁线程的开销。所使用的协程库是绿色的。

协程类似于子例程/线程。 区别在于,一旦调用方调用了子例程/线程,它将永远不会返回到调用方函数。 但是协程可以在执行几段代码后返回到调用方,允许调用方执行一些自己的代码,并返回到它停止执行的协程点,并从那里继续。 ie。协程有多个入口点和出口点

我发现这个链接的解释非常直接。这些答案中没有一个试图解释并发和并行,除了这个答案中的最后一个要点。

什么是并发(程序)?

引用自Joe Armstrong的“编程Erlang”,传奇人物:

并发程序在并行计算机上可能运行得更快。

a concurrent program is a program written in a concurrent programming language. We write concurrent programs for reasons of performance, scalability, or fault tolerance. a concurrent programming language is a language that has explicit language constructs for writing concurrent programs. These constructs are an integral part of programming language and behave the same way on all operating systems. a parallel computer is a computer that has several processing units (CPUs or cores) that can run at the same time.

所以并发性和并行性是不同的。您仍然可以在单核计算机上编写并发程序。分时调度器会让你感觉你的程序正在并发运行。

并发程序有可能在并行计算机中并行运行,但不能保证。操作系统可能只给你一个内核来运行程序。

因此,并发是一个来自并发程序的软件模型,这并不意味着您的程序可以在物理上并行运行。

协程和并发

“协程”一词由两个词组成:“co”(合作)和“routine”(函数)。

A.它实现了并发还是并行?

为了简单起见,让我们在单核计算机上讨论它。

并发性是通过来自操作系统的分时实现的。线程在CPU内核上按照指定的时间框架执行代码。它可以被OS抢占。它也可以将控制权交给操作系统。

另一方面,协程将控制权交给线程内的另一个协程,而不是交给OS。因此,线程内的所有协程仍然利用该线程的时间框架,而不会将CPU核心交给由操作系统管理的其他线程。

因此,您可以认为协程是通过用户而不是通过操作系统(或准并行)实现分时的。协程运行在分配给运行这些协程的线程的同一个核心上。

协程能实现并行吗?如果它是cpu绑定的代码,则不会。就像分时系统一样,它让你感觉它们是平行运行的,但它们的执行是交错的,而不是重叠的。如果它是IO绑定的,是的,它通过硬件(IO设备)实现并行,而不是通过您的代码。

B.与函数调用的区别?

如图所示,它不需要调用return来切换控制。它可以不计回报地付出。协程保存并共享当前函数帧(堆栈)上的状态。因此,它比函数轻量级得多,因为你不需要保存寄存器和局部变量来堆栈,并在调用ret时倒带调用stack。

If you are still confused, here is a very simple way of understanding a co-routine. First off, what is a routine? In a lay man's term, a routine is something that we do again and again (for example, your morning routine). Similarly. in programming languages, a routine is a piece of code that we use again and again, e.g., a function. Now, if you look at the general characteristic of a function or routine (note: I am cautiously using these two terms interchangeably), it takes some inputs and hogs the CPU threads for as long as the function needs to output the result. Meaning, functions or routines are blocking calls in you code. However, a co-routine is a special kind of routine that can co-exist (the "co" part of the word co-routine comes from this) with other routines at the same time and we can make this happen in programming languages with the help of asynchronous programming. In Asynchronous programming, when one co-routine is waiting for something to happen (e.g., disk io), the other co-routine will start working and when this co-routine is in a waiting state the other co-routine will be active ultimately reducing the waiting time of our code.

如果你理解了上面的内容,让我们看看如何在Python中创建协程函数。可以像下面那样定义协程函数-

async def my_coroutine_function():
    return 123

你可以通过在协同程序-前面添加await来调用上面的协同程序

my_result = await my_coroutine_function()

最后,

当你正在看电视节目,广告一出现,你就拿起手机给朋友发短信——你刚刚做的就是异步编程。当你的电视节目(一个合作程序)处于等待状态时,你继续前进,让你的另一个合作程序(给你的朋友发短信)处于激活状态。

在Lua编程中,“协程”部分:

A coroutine is similar to a thread (in the sense of multithreading): it is a line of execution, with its own stack, its own local variables, and its own instruction pointer; but it shares global variables and mostly anything else with other coroutines. The main difference between threads and coroutines is that, conceptually (or literally, in a multiprocessor machine), a program with threads runs several threads in parallel. Coroutines, on the other hand, are collaborative: at any given time, a program with coroutines is running only one of its coroutines, and this running coroutine suspends its execution only when it explicitly requests to be suspended.

所以关键是:协程是“协作的”。即使在多核系统中,也只有一个协程在任何给定时间运行(但多个线程可以并行运行)。协程之间存在不可抢占性,运行中的协程必须显式放弃执行。

关于“并发性”,你可以参考Rob Pike的幻灯片:

并发是独立执行计算的组合。

所以在协程A的执行过程中,它把控制权传递给了协程B。经过一段时间后,协程B又把控制权传递给了协程A。由于协程之间存在依赖关系,它们必须串联运行,所以这两个协程不是并发的。