一、什么事协程?
协程是一个比线程更加轻量级的单位,是组成线程的各个函数。
携程本身没有实体
二、为什么要有协程?
1、为了在单线程内实现并发的效果。
因为Cpython中有一个GIL锁,限制了同一时间点,只能执行一个线程所以想要在执行
一个线程的期间充分利用CPU的性能。
2、并发的本质是什么?
并发就是要交替执行,即:切换 (函数1阻塞就去执行函数2)+ 保存状态(从函数1切换到函数2时依然保存着函数1的状态)
3、cpu为什么要进行切换?
1)因为某个程序阻塞了
2)因为某个时间片用完了
因此,当程序阻塞的时候,为了提高cpu的利用率,就需要在进行IO操作的时候立即切换到其他程序去执行。
三、实现程序切换的方法
greenlet模块:能够实现简单的程序切换,但是无法做到,在IO操作时自动切换
代码:
from greenlet import greenlet import time def play_basketball(name): print('%s一记大帽' % name) time.sleep(1) a2.switch('艾弗森') print('%s一记劈扣' % name) time.sleep(1) a2.switch() def swimming(name): print('%s 在蛙泳' % name) time.sleep(1) a1.switch() print('%s 竟然还会蝶泳' % name) a1 = greenlet(play_basketball) a2 = greenlet(swimming) a1.switch('勒布朗')
gevent模块:可以实现在某函数内部遇到IO操作时,自动切换到其他函数,大大提高了
cpu的利用率。
g = gevent.spawn(func, 参数) 注册一下函数func,返回一个对象g。
gevent.join(g) 等待g指向的函数func执行完毕后,如果在执行过程中遇到IO操作就切换。
gevent.joinall([g1,g2,g3]) 等待[g1,g2,g3]指向的函数func执行完毕
代码:
gevent 只能识别自己的IO操作,不能识别其他的IO操作,
举个列子:遇到gevent.sleep() 就会切换 遇到time.sleep()就不会切换
为了解决这种情况,引入了monkey
from gevent import monkey
gevent.patch_all
from gevent import monkey import gevent import time monkey.patch_all() lst = [] def fn(i): time.sleep(1) print(i) start_time = time.time() for i in range(10): g = gevent.spawn(fn, i) lst.append(g) gevent.joinall(lst) print(time.time() - start_time)