什么是greenlet
greenlet是python的一个C扩展,提供了可自行调度的‘微线程’,即协程。
greenlet初体验
使用pip install greenlet即可安装。
假如有这样一个需求:
定义两个函数test1(),test2()。需要不断的在这两个函数中切换执行,我们如何使用greenlet来实现呢?在greenlet中非常容易,看代码。
from greenlet import greenlet
def test1():
print("1")
gr2.switch()
print("3")
gr2.switch()
def test2():
print("2")
gr1.switch()
print("4")
if __name__ == "__main__":
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
执行结果如下图:
image.png
然后我们整理一下逻辑,看看它是如何实现的?
首先我们定义了两个普通函数test1()和test2(),先不管内部实现了什么,先看程序入口,我们将两个定义好的函数分别传给greenlet(),并用gr1和gr2接受这两个结果,然后用gr1.switch()指定了从哪个协程开始执行。
其实看到这里,我们至少知道了它的执行顺序。我画了简图来帮助自己理解。
image.png
当创建一个greenlet时,首先初始化一个空的栈,switch到这个栈时会传入函数,然后执行函数中的内容,直到遇到了另一个协程的switch命令(比如gr1.switch())将函数挂起,然后去gr1中上次中断的地方继续执行,以此类推。
一些思考
如果入口中没有gr1.switch()这句会怎么样?
入口中如果没有gr1.switch()这句会直接结束程序,因为这指定了从哪个greenlet开始执行。
如果去掉test1()中的最后一个gr2.switch(),为什么不会打印‘4’了?
因为switch表示切换协程,当去掉最后一个gr2.switch()后,直到test1执行完毕就结束了,不会再切换到test2()中继续执行了。
进一步了解greenlet
看看greenlet里面都有什么方法?
pprint(dir(greenlet))
image.png
刨除那些魔法方法,剩的就不多了,先看看都是干啥的。
getcurrent()
这是一个全局函数,可以在任意地方获取当前正在执行的协程对象,比如我们修改之前的函数试试
from greenlet import greenlet, getcurrent
def test1():
print("1")
current_coroutine = getcurrent()
print(current_coroutine)
if gr1 is current_coroutine:
print("this is gr1")
gr2.switch()
print("3")
gr2.switch()
def test2():
print("2")
gr1.switch()
print("4")
if __name__ == "__main__":
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
结果打印了‘this is gr1’,这就说明我们拿到current_coroutine和gr1是同一个对象。
greenlet类
主要方法有getcurrent(), gettrace(), settrace(), switch(), throw()
属性有dead, gr_frame, parent, run, _stack_saved, error
gr.dead 返回true,表示协程已经结束。
gr.run 当greenlet启动时会调用这个callable,如果我们需要继承greenlet时,需要重写该方法。
throw 切换到执行协程后立即抛出异常。
先简单知道,以后慢慢补充~
网友评论