美文网首页生活不易 我用python
tornado.ioloop.IOLoop.instance()

tornado.ioloop.IOLoop.instance()

作者: lpj24 | 来源:发表于2015-01-16 10:10 被阅读2080次

    (代码缩进有点问题  大家可以看源码)

    我们来分析一下tornado.ioloop.IOLoop.instance().start(),学习了tornado后,当启动服务的时候,我一直有一个疑惑,我们看一下源码,IOLoop类中instance()是一个单例模式返回IOLoop实例函数

    @staticmethod

    def instance():

    """Returns a global `IOLoop` instance.

    Most applications have a single, global `IOLoop` running on the

    main thread.  Use this method to get this instance from

    another thread.  To get the current thread's `IOLoop`, use `current()`.

    """

    if not hasattr(IOLoop, "_instance"):

    with IOLoop._instance_lock:

    if not hasattr(IOLoop, "_instance"):

    # New instance after double check

    IOLoop._instance = IOLoop()

    return IOLoop._instance

    然后我们再看一下IOloop类的start()函数

    def start(self):

    """Starts the I/O loop.

    The loop will run until one of the callbacks calls `stop()`, which

    will make the loop stop after the current event iteration completes.

    """

    raise NotImplementedError()

    我们发现并未去做实现,是一个抽象方法,或者你可以去python模块包下修改一下源码,如在start()下print("IOLOOP START"),启动我们发现并未打印或者tornado.ioloop.IOLoop.instance().start().im_class看看start()到底属于那个类,我们发现属于EPollIOLoop类(也可以说是EPollIOLoop或其父类的函数)。我们实例化的IOLoop应该是调用IOloop类的实例啊?

    再看一下EPollIOLoop在tornado.platform.epoll这个模块中

    class EPollIOLoop(PollIOLoop):

        def initialize(self, **kwargs):

            super(EPollIOLoop, self).initialize(impl=select.epoll(), **kwargs

    比较简单,什么都没有,但是它是PollIOLoop类的子类,我们可以断定那个start()函数属于PollIOLoop

    类的,我们就找一下PollIOLoop类的start()函数,比较长就不贴出来了,这个细节不是关注的重点。看一下这个类,我们只能发现是IOLoop的子类实现了它的一些方法,还是从IOLoop来找答案吧,IOLoop类的父类是Configurable在util.py模块

    class Configurable(object):

    """Base class for configurable interfaces.

    A configurable interface is an (abstract) class whose constructor

    acts as a factory function for one of its implementation subclasses.

    The implementation subclass as well as optional keyword arguments to

    its initializer can be set globally at runtime with `configure`.

    By using the constructor as the factory method, the interface

    looks like a normal class, `isinstance` works as usual, etc.  This

    pattern is most useful when the choice of implementation is likely

    to be a global decision (e.g. when `~select.epoll` is available,

    always use it instead of `~select.select`), or when a

    previously-monolithic class has been split into specialized

    subclasses.

    Configurable subclasses must define the class methods

    `configurable_base` and `configurable_default`, and use the instance

    method `initialize` instead of ``__init__``.

    """

    __impl_class = None

    __impl_kwargs = None

    def __new__(cls, **kwargs):

    base = cls.configurable_base()

    args = {}

    if cls is base:

    impl = cls.configured_class()

    if base.__impl_kwargs:

    args.update(base.__impl_kwargs)

    else:

    impl = cls

    args.update(kwargs)

    instance = super(Configurable, cls).__new__(impl)

    # initialize vs __init__ chosen for compatiblity with AsyncHTTPClient

    # singleton magic.  If we get rid of that we can switch to __init__

    # here too.

    instance.initialize(**args)

    return instance

    他是一个接口,第一个函数__new__(),首先我们要知道__new__函数的意义(具体解释大家可以查询),__new__函数是在对象实例化的时候执行返回对象的实例,是不是和__init__构造器类似,其实一个对象实例化的时候有2个过程,第一步是调用__new__函数返回实例,然后实例再去调用__init__函数(子类实例化的时候也是同样的过程,父类的__new__和__init__都会执行,一般都是子类实例去调用)。逐步分析

    1 base = cls.configurable_base(),看看configurable_base(),没有找到(可以编译通过的),对,这是一个接口,既然找不到我们只能去实现类里面去找罗(难道这是接口不能实例化的原因吗?)去IOLoop找到了

    @classmethod

    def configurable_base(cls):

    return IOLoop

    返回的是一个IOLoop类所以base = IOLoop

    if cls is base:

    impl = cls.configured_class()

    if base.__impl_kwargs:

    args.update(base.__impl_kwargs)

    tornado.ioloop.IOLoop.instance()中instance()函数有实例化的动作IOLoop(),所以会调用接口的__new__函数,此时的cls就是IOloop了所以判断为true继续执行,我们可以在当前接口中扎到configure_class

    @classmethod

    def configured_class(cls):

    """Returns the currently configured class."""

    base = cls.configurable_base()

    if cls.__impl_class is None:

    base.__impl_class = cls.configurable_default()

    return base.__impl_class

    它做什么的了,__impl_class在开头就定义了None我们将其理解为实现类所以到base.__impl_class = cls.configurable_default(),cls是什么前面说了IOLoop了,看看该方法

    @classmethod

    def configurable_default(cls):

    if hasattr(select, "epoll"):

    from tornado.platform.epoll import EPollIOLoop

    return EPollIOLoop

    if hasattr(select, "kqueue"):

    # Python 2.6+ on BSD or Mac

    from tornado.platform.kqueue import KQueueIOLoop

    return KQueueIOLoop

    from tornado.platform.select import SelectIOLoop

    return SelectIOLoop

    我们可以在IDLE中看看select模块看看有那些属性,我们发现这些属性都有(不知道windows下有没有,可以试试),"epoll"有的,执行第一个判断,成立,返回了EPollIOLoop类 impl = EPollIOLoop

    instance = super(Configurable, cls).__new__(impl)

    看这一句,如果你要重写一个类的__new__这句话一定要加上并且return,不然不能实例化了。instance = super(Configurable, cls).__new__(EPollIOLoop)返回的是EPollIOLoop实例,约定俗成吧,

    所以最后总结出来instance()函数中IOLoop()其实创建的是EPollIOLoop实例,它调用了父类的start()函数,我想为什么IOloop()生产的是这个实例,我仿照这个过程了写了例子

    #父类,我们将其理解为Configurable接口

    class Myc(object):

    def __init__(self):

    print "构造方"

    def __new__(cls):

    print "myc实例被创建"

    return super(Myc,cls).__new__(Myd)  #默认创建Myd实例

    def start(self):

    print "这是父类的start方法"

    #理解为PollIOLoop

    class Myd(Myc):

    @classmethod

    def print_cls(cls):

    print "子类的一个方法,创建的实例是",cls

    def retu_cls(self):

    return Myd

    #理解为EPollIOLoop继承了Myc

    class mye(Myc):

    def child(self):

    print "这是孙子mye"

    测试一下e = mye()

    myc实例被创建

    说明接口__new__被执行了但是__init__没有被执行,说明生成的不是Myc或子类的实例我们看看e可以调用那些方法,可不可以调用mye的child()函数了,发现不行,它可以调用Myd和Myc的函数,e.__class__()看看<__main__.Myd object at 0xb5ee0f6c>原来mye()创建的是Myd的实例

    相关文章

      网友评论

        本文标题:tornado.ioloop.IOLoop.instance()

        本文链接:https://www.haomeiwen.com/subject/xepcxttx.html