
本文的测试环境是在MacOS,因此使用的多路复用的网络IO为kqueue而不是epoll,对应的IOLoop实例对象也是KQueueIOLoop。
在介绍 Epoll模式 的笔记中,最后写了一个tornado的使用epoll的例子。这个例子是如何工作的呢?下面来读一读tornado的源码。
启动一个tornado server很简单,只需要下面几code:
tornado.ioloop.IOLoop.current() 实际上是创建一个IO循环的对象,这里是KQueueIOLoop,Linux的系统则是EPollIOLoop。
下面是current的源码,该方法目的就是从local线程中获取KQueueIOLoop(如果存在的话,否则则新建一个)
程序首先判断 IOLoop._current对象(_current对象是一个线程local)的instance属性,如果没有current,则调用IOLoop.instance()方法创建一个IOLoop的实例作为currnet返回。由于tornado的包装,实际上IOLoop返回的并不是IOLoop的实例对象,而是KQueueIOLoop实例对象。
为什么IOLoop实例化的对象KQueueIOLoop呢?想知道答案就得揭开IOLoop.instance()神秘面纱,表面上看,该方法创建的IOLoop实例对象,并绑定到IOLoop._instance上。
IOLoop继承自Configurable基类,IOLoop 自身没有常见的初始化"构造函数"( init )。显然需要再查看Configurable基类。不看不知道,一看tornado的作者还真会玩。Configurable是一个设计很精巧的类,通过不同子类的继承来适配。基类在子类创建的时候做一些适配的事情。相比 init , new 称之为构造函数更准确。
IOLoop在创建的时候,通过基类 new 方法调用子类的configurable_base和configurable_default适配不同子类的特性。这里通过IOLoop的configurable_default方法选择了unix系统的kqueue方式。
根据平台确定了impl为kqueue之后,将会通过 new 创建实例对象,就是这一步,创建了KQueueIOLoop而不是IOLoop的对象。Configurable自身不定义initialize。这里就调用了KQueueIOLoop的initialize方法。
KQueueIOLoop的方法很简单,其中实现了一个_KQueue,这个类用于 *** 作unix系统上的kqueue的网络io相关封装,例如注册事件,poll调用等。然后KQueueIOLoop带用其父类(PollIOLoop)的initialize方法。有没有发现,调用的控制权一直在各个父类基类中跳转。大概是 IOLoop ->Configurable ->IOLoop ->KQueueIOLoop ->PollOLoop ->IOLoop ->PolIOLoop。
PollIOLoop继承自IOLoop,PollIOLoop调用其父类的initialize方法。此时调用make_current为None,因此又会调用IOLoop.current()的方法,怎么又是IOLoop.current?我们不就是从客户端逻辑(相对于库)调用这个方法进来的么?注意,不同于第一次客户端调用的时候,当时intances是True。也就是此时直接返回IOLoop._current.instance,前面正是因为current为None,才需要通过IOLoop的创建对象。当然此时current为None,即直接返回None。接下来自然运行make_current方法。
make_current方法干点啥好呢?当然你肯定想到了,既然我们之前IOLoop.current方法是为了获取IOLoop._current.instance,并且一直为None,那么make_current正好填补这个空白,创建一个绑定就好嘛。
的确,make_current把当前的类实例(KQueueIOLoop)创建并绑定。通过前面巧妙的设计,根据平台选择了网络io的模式。接下来还得根据io模式绑定IO监听事件。继续阅读PollIOLoop,可以发现通过add_handler方法喝Waker实现。
add_handler方法处理文件描述符,其中stack_context类通过wrap包装一个上下文类似的东西。具体数据结构没有仔细看,留待日后研究,总而言之,这个方法借助之前的_KQueue类注册网络io事件。
此时,ioloop对象成功的创建。创建ioloop对象之后,server还不回启动,需要调用start启动。在启动之前,也需要通过add_hanndler绑定事件函数。至于start的工作原理,下回再研究。
一个用Python写的相对简单的、可扩展、非阻塞的Web服务器架构,以处理上万的同时的连接口,让实时的Web服务通畅起来。跟现在一些用Python写的Web架构相似,比如Django,但更注重速度,能够处理海量的同时发生的流量欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)