join函数——Gevent源码分析
在使用gevent框架的时候,我们经常会使用join
函数,如下:
def test1(id):
print(id)
gevent.sleep(0)
print(id, 'is done!')
t = gevent.spawn(test1, 't')
t1 = gevent.spawn(test1, 't1')
t.join()
运行结果:
t
t1
t is done!
t1 is done!
但是join是如何工作的呢.. 于是今天晚上我好好研究了下join函数~ 多的不说,正文开始!
join函数
join函数源码在greenlet.py中的Greenlet类的join():
def join(self, timeout=None):
if self.ready(): #检测是否执行完成
return
else:
switch = getcurrent().switch #获得当前greenlet的switch回调函数
self.rawlink(switch)
try:
t = Timeout.start_new(timeout)
try:
result = self.parent.switch()
assert result is self, 'Invalid switch into Greenlet.join(): %r' % (result, )
finally:
t.cancel()
except Timeout as ex:
self.unlink(switch)
if ex is not t:
raise
except:
self.unlink(switch)
raise
从join的源码第六行,跟踪到rawlink
函数:
def rawlink(self, callback):
if not callable(callback):
raise TypeError('Expected callable: %r' % (callback, ))
self._links.append(callback)
if self.ready() and self._links and not self._notifier:
self._notifier = self.parent.loop.run_callback(self._notify_links)
可以看出,这个rawlink
函数的目的只有一个:注册当前greenlet的回调函数(第四行), 当主协程hub还没有run的时候,这个时候的greenlet可以理解为一个上下文(这块涉及到greenlet的底层,还不是很清楚)。
回到join函数。在注册了当前greenlet的回调函数后,主要干的事是第10行:切换到主协程hub
主协程的switch函数的功能我在前面的文章中写过了,不再赘述。它会执行greenlet.switch(self)
,由于当前协程为hub,并且没有运行过run,所以会执行hub.run
函数,源码在hub.py下的Hub类里面(这个函数也在前面的文章中讲过,所以不再详细说明)。在这个函数里面就会执行gevent的一般流程(前面的文章讲过)
如果你已经理解了join函数和gevent的工作原理,那么就可以解释以下函数的输出:
def test1(id):
print(id)
gevent.sleep(0)
print(id, 'is done!')
t = gevent.spawn(test1, 't')
gevent.sleep(0)
输出(为什么没有继续输出t is done!
?):
t
答案:
- 创建子协程t
- 执行到sleep函数,由于此时主协程hub还没有运行hub.run(),sleep函数中,语句
loop.run_callback(waiter.switch)
保存的是当前协程(可以理解为上下文)的回调函数 - 调用
waiter.get()
函数 waiter.get()
函数调用hub.switch()
,切换到主协程hub- 由于主协程没有run,所以执行
hub.run()
函数 - 执行loop.run(),切换到子协程t中
- 执行
_run()
函数,即子协程的任务:我们定义的test1函数 - 当执行完test1中的
sleep(0)
的时候,会回到主协程hub,hub会执行之前保存的回调函数,即回到了上下文,不会再回到主协程hub,所以不会输出t is done!
同理,可以分析这个函数的输出:
def test1(id):
print(id)
gevent.sleep(0)
print(id, 'is done!')
t = gevent.spawn(test1, 't')
gevent.sleep(0)
t.join()
输出:
t
t is done!
还有这个函数:
def test1(id):
print(id)
gevent.sleep(0)
print(id, 'is done!')
t = gevent.spawn(test1, 't')
t1 = gevent.spawn(test1, 't1')
t1.join()
t2 = gevent.spawn(test1, 't2')
输出:
t
t1
t is done!
t1 is done!
提示:注意前文分析的“上下文”这个greenlet协程~
join函数——Gevent源码分析的更多相关文章
- sleep函数——Gevent源码分析
gevent是一个异步I/O框架,当遇到I/O操作的时候,会自动切换任务,从而能异步地完成I/O操作 但是在测试的情况下,可以使用sleep函数来让gevent进行任务切换.示例如下: import ...
- switch函数——Gevent源码分析
在gevent的源码中,经常能看到switch函数.而不同的类中的switch函数有不同的用法 1. greenlet的switch函数 这里面的greenlet是greenlet库中的greenle ...
- 转:[gevent源码分析] 深度分析gevent运行流程
[gevent源码分析] 深度分析gevent运行流程 http://blog.csdn.net/yueguanghaidao/article/details/24281751 一直对gevent运行 ...
- 【Android笔记】Thread类中关于join()方法的源码分析
1.join()方法的作用: 例如有一个线程对象为Thread1,在main()方法中调用Thread1.join()方法可使得当前线程(即主线程)阻塞,而执行Thread1线程. 2.源码分析(以上 ...
- Java字符串分割函数split源码分析
spilt方法作用 以所有匹配regex的子串为分隔符,将input划分为多个子串. 例如: The input "boo:and:foo", for example, yield ...
- 内核堆分配函数brk()源码分析
Evernote公开链接:http://www.evernote.com/shard/s133/sh/5b8d3b26-0e53-4c61-aa43-66f6e87bbcb7/a44096dd557f ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
- jquery2源码分析系列
学习jquery的源码对于提高前端的能力很有帮助,下面的系列是我在网上看到的对jquery2的源码的分析.等有时间了好好研究下.我们知道jquery2开始就不支持IE6-8了,从jquery2的源码中 ...
- [转]jQuery源码分析系列
文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...
随机推荐
- zabbix之2安装编译/基本功能实现
1.安装方式: rpm或者编译都可,rpm可以直接用yum安装. rpm安装的话,根据文件名进行选择即可. 编译的话,不同参数对应不同的组件. 编译安装zabbix:同时安装server和agent, ...
- 2016_ThinkinG of everyDay
2016-2-15:新年的第一篇心情,慢慢更新. 1.以后的文章当然都会是ACM竞赛的题解,但会多写写自己的思考以及总结,因为感觉自己缺少思考这个习惯,有些东西在脑子里也只是一带而过,最后也不会停留多 ...
- 凸包(hd1392)
Surround the Trees Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- BZOJ NOI十连测 第二测 T1
出题人居然是个哲学家.. 26%的程序,太SB了...本来我的想法也是二分+贪心,但是贪心是个怪怪的SX贪心.. #include<algorithm> #include<cstdi ...
- 360云后台(使用HTTP Cache服务器)
工作职责:设计优化HTTP Cache服务器,负载均衡服务器,调度系统等核心系统开发优化CDN系统架构满足流量.性能.成本要求 技能要求: 精通Linux, C/C++语言,HTTP协议精通高性能服务 ...
- bzoj3407 [Usaco2009 Oct]Bessie's Weight Problem 贝茜的体重问题
Description 贝茜像她的诸多姊妹一样,因为从约翰的草地吃了太多美味的草而长出了太多的赘肉.所以约翰将她置于一个及其严格的节食计划之中.她每天不能吃多过H(5≤日≤45000)公斤的干 ...
- AutoResetEvent与ManualResetEvent区别
本文来自:http://www.360doc.com/content/10/1126/10/3267996_72536817.shtml 在.Net多线程编程中,AutoResetEvent和Manu ...
- Lazy方式单列模式,一种线程安全模式的新选择
public class WeProxyClient { private static readonly Lazy<WeProxyClient> list = new ...
- Android 四大组件之 Activity
1 简介 Activity (活动) 即应用程序 显示的 界面.可以通过两种方式 设置显示的内容 1:纯代码方式 2:xml 布局方式 无论哪一种方式,都是通过 setContentView 来设置显 ...
- js 创建html元素 渲染html元素
var p1 = document.getElementById('p1'); //添加的元素类型及属性var newNode = document.createElement("input ...