tornado.ioloop.IOLoop.instance().start()中实例详解

我们来分析一下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

2

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


3.

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的实例


你可能感兴趣的:(instance,tornado,ioloop)