首先,咱們瞭解到tornado自己就是一個高併發的異步框架?那麼這個高併發和異步應該從哪裏看出來呢?咱們應該怎麼用咱們本身的模塊實現異步呢?好吧,一切始於源,就從入口函數看起吧。python
tornado.options.parse_command_line()
這個不用說你們都知道封裝的是哪一塊(從sys 得到輸入解析參數)。git
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
關於這個類的具體內容就有的說了,首先進入Application類看看都是什麼內容。github
self.wildcard_router = _ApplicationRouter(self, handlers) self.default_router = _ApplicationRouter(self, [ Rule(AnyMatches(), self.wildcard_router)
最關鍵的內容就是這塊了,他會把你匹配到的規則和對應的handlers聯繫起來。OK,如今把規則聯繫起來了怎麼運行起來呢?這就是接下來的內容了:web
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
怎麼什麼都沒有啊?這是怎麼回事呢?先接着往下看:app
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()函數開始了服務器的總體運做。 好的,今天就先分析這點內容,給你們,也給本身再次消化的時間。