python 协程
简介:
线程和进程都是抢占式的,即系统调配,有一定时间片;
而协程则是程序自己安排执行顺序,可以主动让出CPU,系统是不知道的,在lua等脚本语言中都有机制。
使用协程的几种方法:
yield
注意协程关键是程序自己安排执行顺序,函数可以通过yield让出执行权。
import time def A(): while 1: print('-----A-----') time.sleep(1) yield() def B(): while 1: print('-----B-----') time.sleep(1) next(a) a = A() B()
greenlet
greenlet是个第三方库,pip可以直接安装,封装了一些接口,但仍然是阻塞的。
from greenlet import greenlet import time def A(): while 1: print('------A-------') time.sleep(1) g2.switch() def B(): while 1: print('------B-------') time.sleep(1) g1.switch() g1 = greenlet(A) # 创建协程g1 g2 = greenlet(B) g1.switch() # 跳转至协程g1
gevent
基于greenlet再次封装的框架,其实还有其他框架。
关键是有个monkey补丁,可以实现非阻塞IO。
import gevent from gevent import monkey # 若不使用monkey补丁,则阻塞将使整个程序阻塞! monkey.patch_all() import time def A(): while 1: print('------A-------') gevent.sleep(1) def B(): while 1: print('------B-------') time.sleep(5) # 关键在这里,这里的睡眠原本将阻塞进程,但由于有monkey补丁,这里变为非阻塞。 gevent.sleep(1) g1 = gevent.spawn(A) # 创建一个协程 g2 = gevent.spawn(B) g1.join() # 等待协程执行结束 g2.join()
关键:
- 导入monkey补丁不可以gevent.monkey.patch_all(),因为monkey模块是个gevent子模块,文件包含关系;
- gevent.sleep(1),这里将放弃CPU控制权1秒,这里将保证至少1秒,睡眠期间即使没有协程占有CPU,睡眠协程也不会占有;
- monkey补丁将修改Python底层的api,这其实对于出问题时找bug会造成一定影响,所以patch_all的参数,将允许你替换一部分IO,将其改成非阻塞。
在IO密集的情况下,协程效率还是非常高的。但注意,协程并不能发挥多核的作用,实际还是单线程的。
【本文章出自博客园willaty,转载请注明作者出处,误差欢迎指出~】