# 协程 协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程那样需要上下文切换来消耗资源,因此协程的开销远远小于线程的开销。 协程是一种“伪多线程” ## python 中的协程 在python中实现协程的办法有很多,这里我简单说两个: ### yield实现 基于Python的生成器的yield和yield form关键字实现协程代码。 ``` def foo(): print("starting...") while True: res = yield 4 print("res:",res) g = foo() print(next(g)) print("*"*20) print(next(g)) #就这么简单的几行代码就让你明白什么是yield,代码的输出这个: starting... 4 ******************** res: None 4 ``` 我直接解释代码运行顺序,相当于代码单步调试: 1. 程序开始执行以后,因为foo函数中有yield关键字,所以foo函数并不会真的执行,而是先得到一个生成器g(相当于一个对象) 2. 直到调用next方法,foo函数正式开始执行,先执行foo函数中的print方法,然后进入while循环 3. 程序遇到yield关键字,然后把yield想想成return,return了一个4之后,程序停止,并没有执行赋值给res操作,此时next(g)语句执行完成,所以输出的前两行(第一个是while上面的print的结果,第二个是return出的结果)是执行print(next(g))的结果, 带yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数,next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方执行的,所以调用next的时候,生成器并不会从foo函数的开始执行,只是接着上一步停止的地方开始,然后遇到yield后,return出要生成的数,此步就结束。 **send()函数** ``` def foo(): print("starting...") while True: res = yield 4 print("res:",res) g = foo() print(next(g)) print("*"*20) print(g.send(7)) 再看一个这个生成器的send函数的例子,这个例子就把上面那个例子的最后一行换掉了,输出结果: starting... 4 ******************** res: 7 4 ``` 先大致说一下send函数的概念:此时你应该注意到上面那个的紫色的字,还有上面那个res的值为什么是None,这个变成了7,到底为什么,这是因为,send是发送一个参数给res的,因为上面讲到,return的时候,并没有把4赋值给res,下次执行的时候只好继续执行赋值操作,只好赋值为None了,而如果用send的话,开始执行的时候,先接着上一次(return 4之后)执行,先把7赋值给了res,然后执行next的作用,遇见下一回的yield,return出结果后结束。   **yield from** 这就有真正用到return了,这个返回的就是return的。 ``` def func1(): yield 1 a = yield from func2() print(a) def func2(): yield 3 return 23 f1 = func1() for item in f1: print(item) #out: # 1 # 3 # 23 ``` 注意:yield form关键字是在Python3.3中引入的。 ### async & awit实现 这是一种比较新的实现方法,由于经过封装后,所以使用比较简单,但是自由度也变低了。不过正常高并发开发,用这个很好。 ``` import asyncio import time async def say_after(delay, what): a = await asyncio.sleep(delay) print(what) async def main(): print(f"started at {time.strftime('%X')}") # await say_after(1, 'hello') # await say_after(2, 'world') s1 = say_after(1, '1') s2 = say_after(2,'2') task = [s1,s2] await asyncio.wait(task) print(f"finished at {time.strftime('%X')}") asyncio.run(main()) ``` 观察输出结果很明显就可以看到结果 ``` out: started at 22:58:31 1 2 finished at 22:58:33 ``` **async**定义一个协程,要执行一个协程,必须用**await**。 具体的使用细节可以去搜一下,python官方文档很齐全。