关于tornado内部实现原理

本文深入探讨了Tornado框架的内部实现原理,重点讲解了其异步与高并发特性的实现方式。从源码角度解析了配置初始化过程、服务器启动流程及I/O循环机制。

首先,我们了解到tornado本身就是一个高并发的异步框架?那么这个高并发和异步应该从哪里看出来呢?我们应该怎么用我们自己的模块实现异步呢?好吧,一切始于源,就从入口函数看起吧。

tornado.options.parse_command_line()

这个不用说大家都知道封装的是哪一块(从sys 获得输入解析参数)。

app = tornado.web.Application(handlers=[(r"/", IndexHandler)])

关于这个类的具体内容就有的说了,首先进入Application类看看都是什么内容。

        self.wildcard_router = _ApplicationRouter(self, handlers)
        self.default_router = _ApplicationRouter(self, [
            Rule(AnyMatches(), self.wildcard_router)

最关键的内容就是这块了,他会把你匹配到的规则和对应的handlers联系起来。OK,现在把规则联系起来了怎么运行起来呢?这就是接下来的内容了:

http_server = tornado.httpserver.HTTPServer(app)

好的,进入HTTPServer类里看看到底发生了什么鬼。首先看这一部分:

class HTTPServer(TCPServer, Configurable,
                 httputil.HTTPServerConnectionDelegate):

记住这个类继承了哪些类以后会用到。然后找到入口函数:

    def __init__(self, *args, **kwargs):
        # Ignore args to __init__; real initialization belongs in
        # initialize since we're Configurable. (there's something
        # weird in initialization order between this class,
        # Configurable, and TCPServer so we can't leave __init__ out
        # completely)
        pass

怎么什么都没有啊?这是怎么回事呢?先接着往下看:

    def initialize(self, request_callback, no_keep_alive=False, io_loop=None,
                   xheaders=False, ssl_options=None, protocol=None,
                   decompress_request=False,
                   chunk_size=None, max_header_size=None,
                   idle_connection_timeout=None, body_timeout=None,
                   max_body_size=None, max_buffer_size=None,
                   trusted_downstream=None):
        self.request_callback = request_callback
        self.no_keep_alive = no_keep_alive
        self.xheaders = xheaders
        self.protocol = protocol
        self.conn_params = HTTP1ConnectionParameters(
            decompress=decompress_request,
            chunk_size=chunk_size,
            max_header_size=max_header_size,
            header_timeout=idle_connection_timeout or 3600,
            max_body_size=max_body_size,
            body_timeout=body_timeout,
            no_keep_alive=no_keep_alive)
        TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,
                           max_buffer_size=max_buffer_size,
                           read_chunk_size=chunk_size)
        self._connections = set()
        self.trusted_downstream = trusted_downstream

怎么创建server是在这个里面呢?这就用到了继承类里的Configurable,其他的两个继承类看单词就知道什么意思了,以后再具体分析,今天就先具体分析Configurable这个类,那么进入Configurable之后呢:

    def __new__(cls, *args, **kwargs):
        base = cls.configurable_base()
        init_kwargs = {}
        if cls is base:
            impl = cls.configured_class()
            if base.__impl_kwargs:
                init_kwargs.update(base.__impl_kwargs)
        else:
            impl = cls
        init_kwargs.update(kwargs)
        instance = super(Configurable, cls).__new__(impl)
        # initialize vs __init__ chosen for compatibility with AsyncHTTPClient
        # singleton magic.  If we get rid of that we can switch to __init__
        # here too.
        instance.initialize(*args, **init_kwargs)
        return instance


    @classmethod
    def configurable_base(cls):
        # type: () -> Any
        # TODO: This class needs https://github.com/python/typing/issues/107
        # to be fully typeable.
        """Returns the base class of a configurable hierarchy.

        This will normally return the class in which it is defined.
        (which is *not* necessarily the same as the cls classmethod parameter).
        """
        raise NotImplementedError()

    @classmethod
    def configurable_default(cls):
        # type: () -> type
        """Returns the implementation class to be used if none is configured."""
        raise NotImplementedError()

    def initialize(self):
        # type: () -> None
        """Initialize a `Configurable` subclass instance.

        Configurable classes should use `initialize` instead of ``__init__``.

        .. versionchanged:: 4.2
           Now accepts positional arguments in addition to keyword arguments.
        """

    @classmethod
    def configure(cls, impl, **kwargs):
        # type: (Any, **Any) -> None
        """Sets the class to use when the base class is instantiated.

        Keyword arguments will be saved and added to the arguments passed
        to the constructor.  This can be used to set global defaults for
        some parameters.
        """
        base = cls.configurable_base()
        if isinstance(impl, (str, unicode_type)):
            impl = import_object(impl)
        if impl is not None and not issubclass(impl, cls):
            raise ValueError("Invalid subclass of %s" % cls)
        base.__impl_class = impl
        base.__impl_kwargs = kwargs

看到这里你有没有豁然开朗的感觉?反正我是挺兴奋的。原来在继承Configurable类的时候,已经在创建的时候完成了。接下来是什么?

tornado.ioloop.IOLoop.instance().start()

这个IOLoop是什么鬼?他是怎么来的呢?请看下面:

class IOLoop(Configurable):
    @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 = cls.configured_class() impl 在这里就是 epoll ,它的生成函数是 configured_class(), 而其方法里又有 base.__impl_class = cls.configurable_default() ,调用了 configurable_default() 。而 Configurable 的 configurable_default()被IOLoop继承后重载,终于实现了epoll的并发大法。最后调用了thread的start()函数开始了服务器的整体运作。 好的,今天就先分析这点内容,给大家,也给自己再次消化的时间。

转载于:https://my.oschina.net/u/2241389/blog/1785172

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值