当前位置: 首页 > 后端技术 > Python

程序员应该如何理解协程

时间:2023-03-25 22:48:45 Python

作为程序员,你一定或多或少听过协程这个词。这项技术近年来越来越多地出现在程序员的视野中,尤其是在高性能高并发领域。当你的同学和同事提到协程的时候,如果你的大脑一片空白,你根本就没有概念。..那么这篇文章就是为你准备的。话不多说,今天的话题就是作为程序员的你应该如何吃透协程。普通函数先来看一个普通函数,这个函数很简单:deffunc():print("a")print("b")print("c")这是一个简单的普通函数,当我们发生什么什么时候调用这个函数?调用funcfunc开始执行,直到returnfunc执行完毕。返回函数A是不是很简单?函数func一直执行到返回,并打印出:abcSoeasy,isthereany,isthereany!非常好!请注意,这段代码是用python编写的,但是对协程的讨论适用于任何语言,我们只是碰巧使用python作为示例,因为它足够简单。那么什么是协程?从普通函数到协程接下来,我们将从普通函数过渡到协程。与只有一个返回点的普通函数不同,协程可以有多个返回点。这是什么意思?voidfunc(){print("a")暂停并返回print("b")暂停并返回print("c")}普通函数下,函数只在执行完print("c")这句话后才执行会返回,但是协程下执行完print("a")后,func会因为“暂停返回”的代码返回调用函数。有些学生可能看起来很困惑。这其中有什么神奇之处吗?我也可以通过写return来返回,像这样:这样写的话return之后的代码是不会执行的。协程之所以神奇,是因为当我们从协程返回时,可以继续调用协程,在协程上一个返回点之后继续执行。这已经够神奇了,就像孙悟空说“叮”一样,函数暂停了:您可以返回调用函数。当调用函数记住协程后,可以再次调用协程,协程会从之前的返回点继续执行。惊人的,在那里,在那里!非常好!只是孙大圣用的公式“定”在编程语言中一般称为yield(其他语言可能有不同的实现,但本质是一样的)。需要注意的是,当一个普通的函数返回时,进程的地址空间中不会保存函数的运行时信息,但是协程返回后,需要保存函数的运行时信息,那么函数的运行时是做什么的state看起来像在内存中?关于此问题,您可以参考_此处_。下面我们用实际代码来看一下协程。Showmethecode下面我们用一个真实的例子来说明,语言使用python,不熟悉的同学不用担心,这里不会有理解的门槛。在python语言中,“fix”这个词还使用了关键字yield,所以我们的func函数就变成了:voidfunc(){print("a")yieldprint("b")yieldprint("c")}注意这时候我们的func不再是一个简单的函数,而是升级为协程,那我们应该怎么使用呢,很简单:1defA():2co=func()#获取协程3next(co)#调用协程4print("infunctionA")#dosomething5next(co)#再次调用协程我们看到虽然func函数没有return语句,也就是说虽然Novalue返回了,但是我们还是可以写co=func()这样的代码,也就是说co就是我们得到的协程。接下来,我们调用协程,使用next(co),运行函数A,看看执行到第3行的结果是什么:a很明显,正如我们所料,协程func是由于print("a")执行yieldpauses然后返回到函数A。接下来是第4行。毫无疑问,函数A正在做自己的事情,所以它会打印:ainfunctinoAisthekeyline。执行到第5行,再次调用协程应该打印什么?如果func是一个普通的函数,那么会执行func的第一行代码,即打印a。但是func不是普通的函数,而是协程。我们之前说过,协程会在之前的返回点继续运行,所以这里应该执行的是func函数第一次yield之后的代码,即print("b")。ainfunctinoab看,协程是一个很神奇的函数,它会记住之前的执行状态,再次调用时,会从上次的返回点继续执行。神奇不神奇,强大不伟大!非常好。图解说明为了让大家更透彻的理解协程,我们再用图解的方式来看一下,首先是普通的函数调用:在这个图中,方框代表函数的指令序列,如果函数不调用任何其他函数,应该从上到下依次执行,但是函数中可以调用其他函数,所以它的执行不是简单的从上到下,箭头线表示执行流程的方向。从图中我们可以看出,我们首先来到了funcA这个函数,执行了一段时间后,发现又调用了另一个函数funcB。这时,控制权就转移到了这个函数上。执行完成后,我们回到main函数的调用点继续执行。这是一个普通的函数调用。接下来是协程。这里,我们还是先在funcA函数中执行,运行一段时间后调用协程,协程开始执行,直到第一个暂停点,然后像普通函数一样返回funcA函数,funcA函数执行又是一些代码和调用注意此时协程不同于普通函数。协程不是从第一条指令开始执行,而是从最后一个挂起点开始执行。执行一段时间后,遇到第二次暂停。此时协程像普通函数一样再次返回到funcA函数,funcA函数执行一段时间后整个程序结束。函数只是协程的特例怎么样?魔术不是魔术。与普通函数不同,协程可以知道它最后一次执行的位置。现在你应该明白了,协程会在函数挂起的时候保存函数的运行状态,并且可以从保存的状态恢复继续运行。听起来很熟悉吗?这不就是操作系统对线程的调度吗?线程也可以挂起。操作系统保存线程的运行状态,然后调度其他线程。之后,当线程再次被分配CPU时,它可以继续运行。就好像它从未被暂停过一样。只不过线程调度是由操作系统实现的,对程序员是不可见的,而协程是在用户态实现的,对程序员是可见的。这就是为什么有人说协程可以理解为用户态线程。这里应该有掌声。也就是说,程序员现在可以扮演操作系统的角色,你可以控制协程什么时候运行,什么时候挂起,也就是说协程的调度权掌握在自己手中。在协程这件事上,调度由你决定。当你在协程中写yield时,你想暂停协程,当你使用next()时,你又想再次运行协程。现在你应该明白为什么函数只是协程的一个特例了。函数实际上只是没有挂点的协程。协程的历史可能有的同学认为协程是一个比较新的技术,但实际上协程的概念早在1958年就已经被提出来了,要知道线程的概念还没有被提出来。1972年,一种编程语言终于实现了这个概念。这两种编程语言分别是Simula67和Scheme。但是协程的概念一直没有流行起来。甚至在1993年,就有人像考古一样写论文,挖掘协程这个古老的技术。因为这个时期没有线程,如果要在操作系统中编写并发程序,就不得不使用协程之类的技术。后来,线程开始出现,操作系统终于开始原生支持程序的并发执行。就是这样。协程逐渐淡出了程序员的视线。直到最近几年,随着互联网的发展,尤其是移动互联网时代的到来,服务器对高并发的要求越来越高,协程才再次回归到技术的主流。所有主流编程语言都已经支持或计划启动Coroutines。现在你应该对协程有了清晰的认识。综上所述,您应该已经了解协程是什么了。但是,还有一个问题没有解决。为什么协程的技术又回来了?协程适用于哪些场景?如何使用它?关于这些问题,下一篇文章会给你答案。我希望这篇文章能帮助你理解协程。