什么是协程?

yes*_*aaj 181 terminology coroutine

什么是协程?它们如何与并发相关?

use*_*714 125

协程和并发在很大程度上是正交的.协同程序是一种通用控制结构,其中流控制在两个不同的例程之间协同传递而不返回.

Python中的'yield'语句就是一个很好的例子.它创造了一个协程.遇到'yield'时,保存函数的当前状态,并将控制权返回给调用函数.然后,调用函数可以将执行转移回让步功能,并且其状态将恢复到遇到"yield"并且将继续执行的程度.

  • 直接调用函数和从协程生成函数并将此函数包装到此协程之间有什么区别? (18认同)
  • “协程是一种通用控制结构,流控制在两个不同的例程之间协同传递而不返回。” <-这是并发性。您要查找的单词是并行性。 (5认同)
  • 可能更好的解释这两个概念在这个背景下并不真正"正交".你绝对可以画出两个概念彼此相似的方式.在两个或更多事物之间传递控制的想法非常相似. (3认同)
  • @tonix 有人告诉我“正交”的意思是“彼此独立”。 (3认同)

Nan*_*iao 71

来自Lua的编程," Coroutines"部分:

协程类似于一个线程(在多线程意义上):它是一个执行线,有自己的堆栈,它自己的局部变量,以及它自己的指令指针; 但它与其他协同程序共享全局变量和其他任何东西.线程和协同程序之间的主要区别在于,从概念上(或在字面上,在多处理器机器中),具有线程的程序并行运行多个线程.另一方面,协同程序是协作的:在任何给定时间,具有协同程序的程序仅运行其协同程序之一,并且此运行协程仅在明确请求被挂起时才暂停其执行.

所以重点是:协同程序是"协作的".即使在多核系统中,在任何给定时间只有一个协程运行(但多个线程可以并行运行).协同程序之间存在非抢占式,运行协程必须明确放弃执行.

对于" concurrency",你可以参考Rob Pike的幻灯片:

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

因此在协程A的执行期间,它将控制传递给协程B.然后经过一段时间后,协程B将控制权传递给协程A.由于协程之间存在依赖关系,并且它们必须串联运行,因此这两个协程不是并发的.

  • 放弃CPU让*其他任务*运行,并告诉某个特定的其他进程是时候执行它们之间有区别.协同程序执行后者.这在任何意义上都不是独立的. (6认同)
  • @ChrisClark我同意你的看法.协同程序是并发的.以下是维基百科的一些引用:*Coroutines与线程非常相似.然而,协同程序是协同多任务的,而线程通常是抢占式多任务.这意味着**它们提供并发性但不提供并行性**.* (5认同)
  • 协同程序不会独立执行.他们轮流,每个人都在等待另一个人完成部分工作.他们积极协调.这与Rob Pikes对并发的定义相反. (3认同)
  • 并且:*协作式多任务处理,也称为非抢占式多任务处理,是一种计算机多任务处理方式,操作系统从不启动从正在运行的进程到另一个进程的上下文切换.相反,进程会定期或在空闲或逻辑阻塞时自动产生控制,以便同时运行多个应用程序.* (3认同)
  • @ ErickG.Hagstrom:虽然它们不是独立执行的,但每个协同程序的逻辑都可以是独立的,对吧?如果它是正确的,它就像在单核CPU上运行的非抢占式操作系统,一个进程必须放弃CPU让其他任务运行. (2认同)
  • 我将不得不同意,最后一句话与答案本身并不相符(实际上,自相矛盾)。整个答案证明,根据定义,协程不是并发的——它们实际上是互斥的(它们中的任何两个都不能“同时执行)”。 (2认同)

mr1*_*011 30

我发现大多数答案太技术性,即使这是一个技术问题.我很难尝试理解协同程序.我有点得到它,但后来我没有得到它.

我发现这里的答案非常有帮助:

https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9

引用Idan Arye的话:

为了建立你的故事,我会这样说:

你开始看动画片,但这是介绍.你没有观看介绍,而是转到游戏并进入在线大厅 - 但它需要3名玩家,只有你和你的妹妹在其中.而不是等待其他玩家加入你切换到你的作业,并回答第一个问题.第二个问题包含指向您需要观看的YouTube视频的链接.你打开它 - 它开始加载.您可以切换回卡通片,而不是等待它加载.介绍结束了,所以你可以观看.现在有广告 - 但同时第三个玩家加入,所以你切换到游戏等等......

我们的想法是,您不仅要快速切换任务,以使其看起来像是在一次性完成任务.您利用等待事情发生的时间(IO)来做其他需要您直接关注的事情.

绝对检查链接,还有更多,我不能引用一切.

  • 非常简单明了的插图。为此+1。 (2认同)
  • 很棒的插图。我编了一个类似的故事——排队等待领取包裹。但今天,你的想法要现实得多,当门到门送货时谁在排队?哈哈 (2认同)

Twi*_*kle 11

Coroutine类似于子程序/线程.不同之处在于,一旦调用者调用了子例程/线程,它就永远不会返回给调用者函数.但是,协程可以在执行一些代码后返回给调用者,允许调用者执行一些自己的代码并返回到协程点,在那里它停止执行并从那里继续执行.即.一个协程有多个入口和出口点


Iza*_*ana 10

我发现这个链接的解释非常简单。除了本答案中的最后一个要点之外,这些答案都没有试图解释并发性与并行性。

  1. 什么是并发(程序)?

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

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

  • 并发程序是用并发编程语言编写的程序。我们出于性能、可伸缩性或容错性的原因编写并发程序。

  • 并发编程语言是一种具有用于编写并发程序的显式语言结构的语言。这些结构是编程语言的一个组成部分,在所有操作系统上的行为方式都相同。

  • 并行计算机是具有多个可以同时运行的处理单元(CPU 或内核)的计算机。

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

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

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

  1. 协程和并发

“coroutine”这个词由两个词组成:“co”(合作)和“routines”(函数)。

一种。它实现了并发还是并行?

简单来说,让我们在单核计算机上讨论它。

并发是通过操作系统的时间共享来实现的。线程在 CPU 内核上为其分配的时间范围内执行其代码。它可以被操作系统抢占。它也可能将控制权交给操作系统。

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

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

协程是否实现了并行性?如果是受 CPU 限制的代码,则不会。与分时共享一样,它让您感觉它们是并行运行的,但它们的执行是交错而不重叠的。如果它是 IO 绑定的,是的,它通过硬件(IO 设备)而不是您的代码实现并行。

湾 与函数调用的区别?

在此处输入图片说明

如图所示,不需要调用return切换控制。它可以在没有return. 协程保存并共享当前函数帧(堆栈)上的状态。因此它比函数轻得多,因为当call ret.


Hea*_*ify 9

如果您仍然感到困惑,这里有一个非常简单的方法来理解co-routine. 首先,什么是routine?用外行人的话来说,例行公事是我们一次又一次做的事情(例如,你早上的例行公事)。相似地。在编程语言中,aroutine是我们一次又一次使用的一段代码,例如a function。现在,如果你看看 a 的一般特征function or routine(注意:我谨慎地交替使用这两个术语),只要函数需要输出结果,它就会需要一些输入并占用 CPU 线程。意思是,functions or routines正在阻止代码中的调用。然而, aco-routine是一种特殊的例程,它可以与其他例程同时共存(“co-routine”一词的“co”部分由此而来),我们可以在编程语言中借助异步编程。在异步编程中,当一个协程正在等待某件事发生(例如,磁盘IO)时,另一个协程将开始工作,并且当该协程处于等待状态时,另一个协程最终将被激活减少我们代码的等待时间。

如果您理解了上述内容,让我们看看如何在 Python 中创建协同例程函数。您可以定义一个协同例程函数,如下所示 -

async def my_coroutine_function():
    return 123

Run Code Online (Sandbox Code Playgroud)

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

my_result = await my_coroutine_function()
Run Code Online (Sandbox Code Playgroud)

总而言之,

当您正在观看电视节目时,广告一出现,您就拿起手机给朋友发短信 - 您刚刚所做的就是异步编程。当你的电视节目(协同例程)处于等待状态时,你继续并激活你的另一个协同例程(给你的朋友发短信)。


Dha*_*ani 8

  • 协同程序是Kotlin语言中的强大功能
  • 协同程序是一种编写异步,非阻塞代码的新方法(以及更多)
  • Coroutine是轻量级的线程.轻量级线程意味着它不会映射到本机线程,因此它不需要在处理器上进行上下文切换,因此它们更快.
  • 它不会映射到本机线程
  • 协同程序和线程都是多任务处理.但不同之处在于线程由操作系统和协同程序由用户管理.

基本上,有两种类型的协同程序:

  1. 无堆栈
  2. Stackful

Kotlin实现无堆栈协程 - 这意味着协同程序没有自己的堆栈,因此它们不会映射到本机线程.

这些是启动协程的功能:

launch{}

async{}
Run Code Online (Sandbox Code Playgroud)

您可以从这里了解更多信息:

https://www.kotlindevelopment.com/deep-dive-coroutines/

https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9


use*_*581 7

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

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

         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-->| 
Run Code Online (Sandbox Code Playgroud)

与多线程解决方案相比:

thread A->|<--A|          |--A-->|
thread B------>|<--B|            |--B-->|
thread C ---------->|<---C|             |C--->|
Run Code Online (Sandbox Code Playgroud)
  • 协程是异步编程的一种实现,异步编程就是用来实现并发的。
  • 许多语言使用协程实现异步编程。其他答案表明 Python、Kotlin、Lua、C++ 已经这样做了。
  • 最有用/通常用于涉及 I/O 限制问题的场景,例如在获取数据时渲染 UI,或从多个数据源下载。

  • 第一个描述完全具有误导性,它传达了一种感觉,多个例程同时运行,这完全不是协程正在做的事情 (2认同)