首先,我们了解到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()函数开始了服务器的整体运作。 好的,今天就先分析这点内容,给大家,也给自己再次消化的时间。