tornado 源码阅读-初步认识

序言

ioloop

源码分析

1.回调 callbacks

他是ioloop回调的基础部分,通过IOLoop.instance().add_callback()添加到self._callbacks
他们将在每一次loop中被运行.

主要用途是将逻辑分块,在适合时机将包装好的callback添加到self._callbacks让其执行.

例如ioloop中的add_future

future对象得到result的时候会调用future.add_done_callback添加的callback,再将其转至ioloop执行

2.定时器 due_timeouts

这是定时器,在指定的事件执行callback.
跟1中的callback类似,通过IOLoop.instance().add_callback

在每一次循环,会计算timeouts回调列表里的事件,运行已到期的callback.
当然不是无节操的循环.

因为poll操作会阻塞到有io操作发生,所以只要计算最近的timeout,
然后用这个时间作为self._impl.poll(poll_timeout)poll_timeout ,
就可以达到按时运行了

但是,假设poll_timeout的时间很大时,self._impl.poll一直在堵塞中(没有io事件,但在处理某一个io事件),
那添加刚才1中的callback不是要等很久才会被运行吗? 答案当然是不会.
ioloop中有个waker对象,他是由两个fd组成,一个读一个写.
ioloop在初始化的时候把waker绑定到epoll里了,add_callback时会触发waker的读写.
这样ioloop就会在poll中被唤醒了,接着就可以及时处理timeout callback

用这样的方式也可以自己封装一个小的定时器功能玩玩

3.io事件的event loop

处理epoll事件的功能
通过IOLoop.instance().add_handler(fd, handler, events)绑定fd event的处理事件
httpserver.listen的代码内,
netutil.py中的netutil.pyadd_accept_handler绑定accept handler处理客户端接入的逻辑

如法炮制,其他的io事件也这样绑定,业务逻辑的分块交由ioloopcallbackfuture处理

关于epoll的用法的内容.详情见我第一篇文章吧,哈哈

总结

ioloop由callback(业务分块), timeout callback(定时任务) io event(io传输和解析) 三块组成,互相配合完成异步的功能,构建gen,httpclient,iostream等功能

串联大致的流程是,tornado 绑定io event,处理io传输解析,传输完成后(结合Future)回调(callback)业务处理的逻辑和一些固定操作 . 定时器则是较为独立的模块

Futrue

个人认为Futuretornado仅此ioloop重要的模块,他贯穿全文,所有异步操作都有他的身影
顾名思义,他主要是关注日后要做的事,类似jqueryDeferred

一般的用法是通过ioloopadd_future定义futuredone callback,
futureset_result的时候,futuredone callback就会被调用.
从而完成Future的功能.

具体可以参考gen.coroutine的实现,本文后面也会讲到

他的组成不复杂,只有几个重要的方法
最重要的是 add_done_callback , set_result

tornadoFutureioloop,yield实现了gen.coroutine

1. add_done_callback

ioloopcallback类似 , 存储事件完成后的callbackself._callbacks

2.set_result

设置事件的结果,并运行之前存储好的callback

为了验证之前所说的,上一段测试代码

运行结果:

gen.coroutine

接着继续延伸,看看coroutine的实现
gen.coroutine实现的功能其实是将原来的callback的写法,用yield的写法代替. 即以yield为分界,将代码分成两部分.
如:

运行结果:

源码分析

接下来分析下coroutine的实现

如源码所示,func运行的结果是GeneratorType ,yielded = next(result),
运行至原函数的yield位置,返回的是原函数func内部 yield 右边返回的对象(必须是FutureFuturelist)给yielded.
经过Runner(result, future, yielded) 对yielded进行处理.
在此就 贴出Runner的代码了.
Runner初始化过程,调用handle_yield, 查看yielded是否已done了,否则add_future运行Runnerrun方法,
run方法中如果yielded对象已完成,用对它的gen调用send,发送完成的结果.
所以yielded在什么地方被set_result非常重要,
当被set_result的时候,才会send结果给原func,完成整个异步操作

详情可以查看tornado 中重要的对象 iostream,源码中iostream的 _handle_connect,如此设置了连接的result.

最后贴上一个简单的测试代码,演示coroutine,future的用法

运行结果:

为什么代码中个yield都起作用了? 因为Runner.run里,最后继续用handle_yield处理了send后返回的yielded对象,意思是func里可以有n干个yield操作

总结

至此,已完成tornado中重要的几个模块的流程,其他模块也是由此而来.写了这么多,越写越卡,就到此为止先吧,

最后的最后的最后

啊~~~~~~好想有份工作女朋友啊~~~~~

1 2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部