一、协程实现
线程和协程
既然我们上面也说了,协程也被称为微线程,下面对比一下协程和线程:
线程之间需要上下文切换成本相对协程来说是比较高的,尤其在开启线程较多时,但协程的切换成本非常低。
同样的线程的切换更多的是靠操作系统来控制,而协程的执行由我们自己控制
我们通过下面的图更容易理解:
从上图可以看出,协程只是在单一的线程里不同的协程之间切换,其实和线程很像,线程是在一个进程下,不同的线程之间做切换,这也可能是协程称为微线程的原因吧
继续分析协程:
既然Gevent用的是Greenlet,我们通过下图来理解greenlet:
每个协程都有一个parent,最顶层的协程就是man thread或者是当前的线程,每个协程遇到IO的时候就把控制权交给最顶层的协程,它会看那个协程的IO event已经完成,就将控制权给它。
from greenlet importgreenletdeftest1(x,y):
z= gr2.switch(x+y)print(z)deftest2(u):print(u)
gr1.switch(42)
gr1=greenlet(test1)
gr2=greenlet(test2)
gr1.switch("hello",'world')
greenlet(run=None, parent=None): 创建一个greenlet实例.
gr.parent:每一个协程都有一个父协程,当前协程结束后会回到父协程中执行,该 属性默认是创建该协程的协程.
gr.run: 该属性是协程实际运行的代码. run方法结束了,那么该协程也就结束了.
gr.switch(*args, **kwargs): 切换到gr协程.
gr.throw(): 切换到gr协程,接着抛出一个异常.
下面是gevent的一个例子:
importgeventdeffunc1():print("start func1")
gevent.sleep(1)print("end func1")deffunc2():print("start func2")
gevent.sleep(1)print("end func2")
gevent.joinall(
[
gevent.spawn(func1),
gevent.spawn(func2)
]
)
二、多协程
简单的多协程
importgeventdeffunc1():print("start func1")