首页

    tornado分析-ioloop overview

    标签:python

    version:5.1

    IOLoop启动

    tornado.ioloop.IOLoop.current().start()
    
    try:
        import asyncio
    except ImportError:
        asyncio = None
    
    class IOLoop(Configurable):
        # In Python 2, _current.instance points to the current IOLoop.
        _current = threading.local()
    
        # In Python 3, _ioloop_for_asyncio maps from asyncio loops to IOLoops.
        _ioloop_for_asyncio = dict()
    
        @staticmethod
        def current(instance=True):
            if asyncio is None:
                current = getattr(IOLoop._current, "instance", None)
                if current is None and instance:
                    current = IOLoop()
                    if IOLoop._current.instance is not current:
                        raise RuntimeError("new IOLoop did not become current")
            else:
                try:
                    loop = asyncio.get_event_loop()
                except (RuntimeError, AssertionError):
                    if not instance:
                        return None
                    raise
                try:
                    return IOLoop._ioloop_for_asyncio[loop]
                except KeyError:
                    if instance:
                        from tornado.platform.asyncio import AsyncIOMainLoop
                        current = AsyncIOMainLoop(make_current=True)
                    else:
                        current = None
            return current
    
        def start(self):
            raise NotImplementedError()
    

    可以看到,如果

    • 有asyncio实现(3.4+)
    from tornado.platform.asyncio import AsyncIOMainLoop
    current = AsyncIOMainLoop(make_current=True)
    
    • 没有的话
    current = IOLoop()
    

    注意到IOLoop没有实现start方法,但是继承了Configurable,Configurable重写了__new__方法
    调用IOLoop(),__new__方法的第1个参数是准备实例化的类,所以这里cls是IOLoop类

    class Configurable(object):
        __impl_class = None  # type: type
    
        def __new__(cls, *args, **kwargs):
            base = cls.configurable_base()
            ...
            if cls is base:
                impl = cls.configured_class()
            ...
            if impl.configurable_base() is not base:
                # The impl class is itself configurable, so recurse.
                return impl(*args, **init_kwargs)
            instance = super(Configurable, cls).__new__(impl)
            instance.initialize(*args, **init_kwargs)
            return instance
    
        @classmethod
        def configured_class(cls):
            base = cls.configurable_base()
            if base.__dict__.get('_Configurable__impl_class') is None:
                base.__impl_class = cls.configurable_default()
            return base.__impl_class
    

    进入第8行,第8行最终调用下面的IOLoop.configurable_default(),根据是否有asyncio实现,确定实现类(AsyncIOLoopPollIOLoop),返回给impl
    cls只要定义了configurable_default方法,并且该方法返回的不是cls本身,就会进入第12行,实例化impl。IOLoop类就是这样

    class IOLoop(Configurable):
        ...
        @classmethod
        def configurable_base(cls):
            return IOLoop
    
        @classmethod
        def configurable_default(cls):
            if asyncio is not None:
                from tornado.platform.asyncio import AsyncIOLoop
                return AsyncIOLoop
            return PollIOLoop
    

    假设上面IOLoop.configurable_default()返回给impl的是PollIOLoop类,继承关系PollIOLoop->IOLoop->Configurable,实例化impl(PollIOLoop)也会调用Configurable的__new__方法,此时__new__方法的第1个参数cls是PollIOLoop类了,PollIOLoop类也定义了configurable_default方法

    class PollIOLoop(IOLoop):
        ...
        @classmethod
        def configurable_base(cls):
            return PollIOLoop
    
        @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
    

    这样impl会是EPollIOLoop,KQueueIOLoop,SelectIOLoop之一,但是它们都没有定义configurable_base方法,只能调用父类PollIOLoop的方法,所以这次

    impl.configurable_base() is base
    

    执行后面代码,实例化impl

    class Configurable(object):
        def __new__(cls, *args, **kwargs):
            ...
            if impl.configurable_base() is not base:
                # The impl class is itself configurable, so recurse.
                return impl(*args, **init_kwargs)
            instance = super(Configurable, cls).__new__(impl)
            instance.initialize(*args, **init_kwargs)
            return instance
    

    值得一提的是Configurable的子类必须实现configurable_baseconfigurable_default方法,还有定义initialize方法以替代__init__

    core method

    这些核心方法都是子类实现的

    class IOLoop(Configurable):
        def close(self, all_fds=False):
        def start(self):
        def stop(self):
    
        def add_handler(self, fd, handler, events):
        def update_handler(self, fd, events):
        def remove_handler(self, fd):
        ...
    

    具体的

    • 如果python版本是3.4+,支持asyncio,使用asyncio.BaseAsyncIOLoop作为实现
    • 否则使用ioloop.PollIOLoop调用Linux 2.5+的epoll作为实现

    不定期更新