深度分析gevent运行流程
来源:互联网 发布:淘宝运营一般要学多久 编辑:程序博客网 时间:2024/06/11 17:18
一直对gevent运行流程比较模糊,最近看源码略有所得,不敢独享,故分享之。
gevent是一个高性能网络库,底层是libevent,1.0版本之后是libev,核心是greenlet。gevent和eventlet是亲近,唯一不同的是eventlet是自己实现的事件驱动,而gevent是使用libev。两者都有广泛的应用,如OpenStack底层网络通信使用eventlet,goagent是使用gevent。
也许大家会好奇,为什么采用这种模式,为什么每次都要切换到hub?我想理由有二:
1.hub是事件驱动的核心,每次切换到hub后将继续循环事件。如果在一个greenlet中不出来,那么其它greenlet将得不到调用。
2.维持两者关系肯定比维持多个关系简单。每次我们所关心的就是hub以及当前greenlet,不需要考虑各个greenlet之间关系。
我们看看最简单的gevent.sleep发生了什么?
我们先想想最简单的sleep(0)该如何调度?根据上面很明显
1.向事件循环注册当前greenlet的switch函数
2.切换到hub,运行主事件循环
当seconds小于等于0时,loop.run_callback(waiter.switch)即是将当前greenlet的switch注册到loop,使用waiter.get()切换到hub。那么很明显,
当切换到hub后当调用刚注册的回调(waiter.switch)回到刚刚sleep所在的greenlet。
不熟悉Waiter的童鞋可能对上面说的有点模糊,下面我们好好看看Waiter是什么。
timer.start(result.switch, 'hello from Waiter')我们向hub的主循环注册一个0.1s的定时器,回调为result.switch,然后将执行result.get(),此时过程代码如下:将把self.greenlet设置为当前greenlet,然后通过self.hub.switch()切换到主循环,很明显在主循环中将回调result.switch,看代码:拿到刚保存的greenlet,然后切换到greenlet.switch(),返回到我们刚调用reuslt.get()方法。通过上面assert我们也可以看出这是在hub中调用的。
通过以上分析,小伙伴们肯定都懂了gevent的执行流程了。
这里有个问题,如果上面先发生result.switch,那又该如何呢?就像下面这样:
我想聪明的你,打开hub.py再看看源码肯定就明白了(上面Waiter代码是我特意简化的)。既然我们知道了gevent运行流程,下面我们看看gevent.spawn和join到底做了什么?
gevent.spawn其实就是Greenlet.spawn,所以gevent.spawn就是创建一个greenlet,并将该greenlet的switch()加入hub主循环回调。
通过下面代码证明:
将输出:bar,我们通过sleep切换到hub,然后hub将运行我们添加的回调talk,一切正常。
此时不要沾沾自喜,如果下面代码也觉得一切正常再高兴也不迟。
这次还是输出:bar,有点不对劲啊,应该输出两个bar才对,为什么为导致这样呢?
我们来好好分析流程:
1.gevent.spawn注册回调talk
2.然后最后一行gevent.sleep(0)注册当前greenlet.switch(最外面的)到hub,然后切换到hub
3.hub执行回调talk,打印"bar",此时gevent.sleep再次将g1.switch注册到hub,同时切换到hub
4.由于第2步最外层greenlet现注册,所以将调用最外层greenlet,此时很明显,程序将结束。因为最外层greenlet并不是hub的子greenlet,
所以died后并不会回到父greenlet,即hub
你可能会说那我自己手动切换到hub不就可以了吗?这将导致主循环结束不了的问题。
程序输出:虽然成功的输出了两次“bar",但也导致了更为严重的问题。这也就是join存在的价值,我们看看join是如何做到的?
从代码中可以看出,join会保存当前greenlet.switch到一个队列中,并注册_notify_links回调,然后切换到hub,在_notify_links回调中将依次调用先前注册在队列中的回调。
而我们调用g1.join()将会把最外层greenlet.switch注册到队列中,当回调时就顺利结束程序了。很完美!!!
- 深度分析gevent运行流程
- [gevent源码分析] 深度分析gevent运行流程
- gevent调度流程解析
- gevent调度流程解析
- gevent调度流程解析
- gevent调度流程解析
- gevent调度流程解析
- gevent的调度流程
- gevent调度流程解析
- Hadoop运行流程分析
- Hadoop运行流程分析
- WordPress 运行流程分析
- Hadoop运行流程分析
- SpringMVC运行流程分析
- katch分析-运行流程
- struts2运行流程分析
- Struts2-运行流程分析
- Struts2运行流程分析
- 34-丑数
- Java开发中的23种设计模式--工厂
- xml的schema约束
- 安装调试gitlab/gitlab-ce容器时遇到的502 Whoops, GitLab is taking too much time to respond
- mac 安装超级vim报错ImportError: dlopen(/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Version
- 深度分析gevent运行流程
- Appium Python API 汇总
- 我为什么会开这个博客?
- 使用jmeter+ant进行接口集成测试,输出测试报告的方法
- ARM TK1 安装kinect驱动
- Linux的常用命令(重点)
- 软件重构与设计模式培训笔记
- centos6默认python2.6升级2.7 卸载python2.6升级2.7
- Android权限管理