python生成器中用到的 yield item 具有2个含义“产出”和“让步”。yield item这行代码会产出一个值,提供给next()调用方;此外还会做出让步,即暂停执行生成器,让调用方继续工作,直到需要使用另一个值时,才会回到生成器上次退出的地方继续执行。
从句法上看,协程与生成器类似,都是包含yield关键字的函数。但在协程中,yield表达式通常为:data = yield,可以产出值,也可以不产出(如果yield关键字后面没有表达式,那么生成器产出None)。此外,协程通常会从调用方接收数据,调用方把数据提供给协程使用.send(data)方法。
yield关键字甚至还可以不接收或传出数据。不管数据如何流动,yield都是一种流程控制工具,使用它可以实现协作式多任务:协程可以把控制器让步给中心调度程序,从而激活其它的协程。
一. 协程的概念
协程(Coroutine),又称微线程,纤程,但协程本质上是一个线程在运行。线程比进程轻量,而协程比线程还要轻量;多线程在同一个进程中运行,而协程通常也在在同一个线程中运行。
由于CPython解析器的GIL原因,多线程的效率受到了很大制约,并且在类*inux系统中,创建线程的开销并不比进程小。后来人们发现通过yield来中断代码片段的执行, 同时交出了CPU的使用权,于是线程的概念产生了,并在python3.4中正式引入。协程通过应用程序,记录上下文栈区,实现在程序执行过程中的跳跃执行。由此可以选择不阻塞的部分执行以提升运行效率。和多线程相比,协程具有如下优点:
- 线程是系统级别的它们由操作系统调度,而协程则是程序级别的由程序根据需要自己调度;
- 资源消耗少,无需多线程那样进行多核间的切换;
- 无需同步互斥操作;
- 没有C10K问题,IO并发性好,一个CPU支持上万的协程都不是问题,所以很适合用于高并发处理。
协程的缺点:
-
无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上。当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
-
进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
二. 使用yield实现协程
本部分使用到的主要方法总结如下: