python之协程
一、什么协程
协程是指在单线程下实现并发,意思就是在一个线程中,实现任务之间的来回切换。我们之前讲的进程、线程,遇到IO阻塞,都是由操作系统来调度进行切换,不是有我们能控制的,但协程就是有我们来决定在哪进行切换。
二、用生成器实现任务之间的切换
import time
def fun1(): for i in range(10): print('%s号学生'%i)
time.sleep(1) yield def fun2(): g=fun1() for n in range(10): g.__next__() print('你好啊,%s号'%n)
time.sleep(1) fun2()
这种模式虽然实现了任务间的切换,我们可以看到最终时间并没减少,也没实现并发
三、用greenlet实现任务之间的切换
import greenlet,time def fun1(): print('1111') g2.switch() time.sleep(1) print('2222') g2.switch() def fun2(): print('33333') g1.switch() time.sleep(1) print('4444') g1=greenlet.greenlet(fun1) g2=greenlet.greenlet(fun2) fun1()
这也实现了任务间的切换,但最终运行时间也没缩短
四、协程的实现
1,gevent模块的使用
#用法 g1=gevent.spawn(func,1,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的,spawn是异步提交任务 g2=gevent.spawn(func2) g1.join() #等待g1结束,上面只是创建协程对象,这个join才是去执行 g2.join() #等待g2结束 有人测试的时候会发现,不写第二个join也能执行g2,是的,协程帮你切换执行了,但是你会发现,如果g2里面的任务执行的时间长,但是不写join的话,就不会执行完等到g2剩下的任务了 #或者上述两步合作一步:gevent.joinall([g1,g2]) g1.value#拿到func1的返回值
,2,协程的实现
#from gevent import monkey;monkey.patch_all()
import gevent,time #引入一个gevent模块 def fun1(): print('1111') gevent.sleep(1) #time.sleep(1) print('2222') def fun2(): print('333') gevent.sleep(1) #time.sleep(1) print('4444') g1=gevent.spawn(fun1,) #异步提交任务 g2=gevent.spawn(fun2,) gevent.joinall([g1,g2]) #等待
整个过程是:异步提交了fun1,和fun2。假如fun1先执行,先打印‘1111’,遇到IO,切换到fun2,打印‘333’,遇到IO,等到fun1的IO过了之后有执行fun1,打印‘2222’。此时fun2的IO也过了,也就执行fun2,打印‘4444’。
fun1的IO是不会受到影响的,fun2也是,都在异步执行的
进程线程的任务切换是由操作系统自行切换的,你自己不能控制
协程是通过自己的程序(代码)来进行切换的,自己能够控制,只有遇到协程模块能够识别的IO操作的时候,程序才会进行任务切换,实现并发效果,如果所有程序都没有IO操作,那么就基本属于串行执行了。