什么是协程?它们与并发有何关系?
什么是协程?它们与并发有何关系?
Answers:
协程和并发在很大程度上是正交的。协程是一种通用的控制结构,流控制在两个不同的例程之间协同传递而不返回。
Python中的“ yield”语句就是一个很好的例子。它创建一个协程。遇到“ yield”时,将保存函数的当前状态,并将控制权返回给调用函数。然后,调用函数可以将执行转移回给yield函数,并且其状态将恢复到遇到“ yield”的点,并且执行将继续。
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.
<-这是并发。您要查找的单词是并行性。
orthogonal = Not similar to each other
吗?
orthogonal
意思是“彼此独立”。
从在Lua编程 “ Coroutines
”部分:
协程类似于线程(在多线程意义上):它是一条执行线,具有自己的堆栈,自己的局部变量和自己的指令指针;但是它与其他协程共享全局变量,并且几乎共享其他任何变量。线程和协程之间的主要区别在于,从概念上(或从字面上看,在多处理器计算机中),具有线程的程序并行运行多个线程。另一方面,协程是协作的:在任何给定时间,具有协程的程序仅运行其协程中的一个,并且该运行的协程仅在显式请求暂停时才暂停其执行。
关键是:协程是“协作的”。即使在多核系统中,任何给定时间都只有一个协程正在运行(但是多个线程可以并行运行)。协程之间是非抢占式的,正在运行的协程必须显式放弃执行。
对于“ concurrency
”,您可以参考Rob Pike的幻灯片:
并发是独立执行计算的组成。
因此,在协程A执行期间,它会将控制权交给协程B。然后,一段时间后,协程B将控制权交给协程A。由于协程之间存在依赖关系,它们必须串联运行,因此两个协程不是并发的。
尽管这是一个技术问题,但我发现大多数答案都过于技术化。我很难理解协程。我有点理解,但是后来却又不同了。
我发现这里的答案非常有帮助:
https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9
引用Idan Arye的话:
为了建立您的故事,我会这样说:
您开始看动画片,但这是介绍。无需观看介绍视频,而是切换到游戏并进入在线大厅-但它需要3个玩家,并且只有您和您的妹妹在其中。无需等待其他玩家加入,而是切换到家庭作业,然后回答第一个问题。第二个问题有指向您需要观看的YouTube视频的链接。您打开它-它开始加载。无需等待加载,您可以切换回卡通。简介已经结束,因此您可以观看。现在有商业广告-但与此同时有第三位玩家加入,所以您切换到游戏,依此类推...
这样做的想法是,您不只是快速切换任务就可以让您看起来好像一次完成所有任务。您可以利用等待事件发生的时间(IO)来做其他需要您直接注意的事情。
绝对检查链接,还有更多我无法引用的内容。
基本上,协程有两种类型:
Kotlin实现了无堆栈的协程—这意味着协程没有自己的堆栈,因此它们不映射在本机线程上。
这些是启动协程的功能:
launch{}
async{}
您可以从这里了解更多信息:
https://www.kotlindevelopment.com/deep-dive-coroutines/
https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9
从Python协程:
Python协程的执行可以在许多地方暂停和恢复(请参阅协程)。在协程函数的主体内部,await和async标识符成为保留关键字。await表达式,for和async with只能在协程函数体中使用。
一个协同程序是可以暂停执行中的功能恢复 以后。协程是无堆栈的:它们通过返回到调用方来挂起执行。这允许异步执行的顺序代码(例如,在没有显式回调的情况下处理非阻塞I / O),并且还支持延迟计算的无限序列和其他用途的算法。
与其他人的答案比较:
我认为,后面的续集是一个核心区别,就像@Twinkle一样。
尽管文档的许多字段仍在进行中,但是,此部分与大多数答案类似,除了@Nan Xiao的
另一方面,协程是协作的:在任何给定时间,具有协程的程序仅在运行其协程中的一个,并且该运行的协程仅在显式请求暂停时才暂停其执行。
由于它是从Lua的Program中引用的,所以它可能与语言有关(目前还不熟悉Lua),因此并非所有文档都只提到了一部分。
与并发的关系:协程(C ++ 20)
有一个“执行”部分。在此引用太长了。
除了细节之外,还有几种状态。
When a coroutine begins execution
When a coroutine reaches a suspension point
When a coroutine reaches the co_return statement
If the coroutine ends with an uncaught exception
When the coroutine state is destroyed either because it terminated via co_return or uncaught exception, or because it was destroyed via its handle
作为@Adam Arold在@ user217714的回答下的评论。它是并发的。
但这不同于多线程。
来自std :: thread
线程允许多个功能同时执行。线程在构造关联的线程对象(等待任何OS调度延迟)后立即开始执行,从作为构造函数参数提供的顶级函数开始。顶级函数的返回值将被忽略,如果它通过引发异常终止,则将调用std :: terminate。顶级函数可以通过std :: promise或通过修改共享变量(可能需要同步,请参见std :: mutex和std :: atomic)将其返回值或异常传达给调用方。
由于它是并发的,因此它就像多线程一样工作,尤其是在不可避免的情况下(从OS的角度来看),这就是为什么它令人困惑。
我发现此链接的解释很简单。除了该答案的最后一个要点之外,这些答案均未尝试解释并发与并行性。
乔·阿姆斯特朗(Joe Armstrong)在“编程Erlang”一书中引用了以下传奇人物:
并发程序可以在并行计算机上更快地运行。
并发程序是用并发编程语言编写的程序。我们出于性能,可伸缩性或容错性的原因而编写并发程序。
并发编程语言是一种具有用于编写并发程序的显式语言构造的语言。这些构造是编程语言的组成部分,并且在所有操作系统上的行为均相同。
并行计算机是具有多个可以同时运行的处理单元(CPU或内核)的计算机。
因此,并发与并行性并不相同。您仍然可以在单核计算机上编写并发程序。分时调度程序会让您感觉程序正在同时运行。
并发程序有可能在并行计算机中并行运行,但不能保证。操作系统可能只给您一个核心来运行您的程序。
因此,并发是来自并发程序的软件模型,并不意味着您的程序可以物理并行运行。
“协程”一词由两个词组成:“合作”(合作)和“例程”(功能)。
一个。它实现并发还是并行?
简单来说,让我们在单核上进行讨论计算机。
并发是通过OS的分时实现的。线程在其分配的时间范围内在CPU内核上执行其代码。它可以被操作系统抢占。它还可能会控制OS。
另一方面,协程可以控制线程中的另一个协程,而不是OS。因此,线程中的所有协程仍会利用该线程的时间范围,而不会将CPU内核让给OS管理的其他线程。
因此,您可以想到协程是由用户而不是由OS(或准并行性)实现的时分。协程在分配给运行这些协程的线程的同一内核上运行。
协程是否达到并行性?如果是CPU绑定代码,则不会。就像分时度假一样,您可以感觉到它们并行运行,但是它们的执行交错而不重叠。如果是IO绑定的,是的,它是通过硬件(IO设备)而不是通过代码并行实现的。
b。函数调用的区别?
如图所示,不需要调用return
即可切换控件。没有可以屈服return
。协程在当前功能框(堆栈)上保存并共享状态。因此,它比函数轻巧得多,因为您不必保存寄存器和局部变量以在时堆叠和回退调用栈call ret
。
我将扩展@ user21714的答案。协程是不能同时运行的独立执行路径。它们依靠控制器(例如python
控制器库)来处理这些路径之间的切换。但是,为了做到这一点,协程本身需要调用yield
要使或类似的结构来暂停其执行。
相反,线程在独立的计算资源上运行并且彼此并行。由于它们使用不同的资源,因此无需调用yield即可继续执行其他执行路径。
您可以通过启动一个多线程程序(例如,一个jvm
应用程序)来看到这种效果,其中所有8个core i7
超线程内核都在其中被利用:在Activity Monitor
或中,您可能会看到797%的利用率Top
。相反,在运行典型python
程序(甚至使用coroutines
或python threading
)时,利用率将达到100%。即一台机器超线程。