2.開始Tornado的源碼分析之旅

Tornado 是由 Facebook 開源的一個服務器“套裝”,適合於做 python 的 web 或者使用其本身提供的可擴展的功能,完成了不完整的 wsgi 協議,可用於做快速的 web 開發,封裝了 epoll 性能較好。文章主要以分析 tornado 的網絡部分即異步事件處理與上層的 IOstream 類提供的異步IO,其他的模塊如 web 的 tornado.web 以後慢慢留作分析。

下面開始我們的 Tornado 之旅,看源代碼之前必定需要有一份源碼了,大家可以去官網下載一份。這裏分析的是 3.1.1。

Tornado 的源碼組織如下:

tornado網絡部分最核心的兩個模塊就是ioloop.py與iostream.py,我們主要分析的就是這兩個部分。

  • ioloop.py 主要的是將底層的epoll或者說是其他的IO多路複用封裝作異步事件來處理。
  • iostream.py主要是對於下層的異步事件的進一步封裝,爲其封裝了更上一層的buffer(IO)事件。

我們先來看看 ioloop(文檔地址:http://www.tornadoweb.org/en/stable/ioloop.html):

We use epoll (Linux) or kqueue (BSD and Mac OS X) if they are available, or else we fall back on select(). If you are implementing a system that needs to handle thousands of simultaneous connections, you should use a system that supports either epoll or kqueue.

Example usage for a simple TCP server:

01 import errno
02 import functools
03 import ioloop
04 import socket
05  
06 def connection_ready(sock, fd, events):
07     while True:
08         try:
09             connection, address = sock.accept()
10         except socket.error, e:
11             if e.args[0not in (errno.EWOULDBLOCK, errno.EAGAIN):
12                 raise
13             return
14         connection.setblocking(0)
15         handle_connection(connection, address)
16  
17 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
18 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
19 sock.setblocking(0)
20 sock.bind(("", port))
21 sock.listen(128)
22  
23 # 創建一個ioloop 實例
24 io_loop = ioloop.IOLoop.instance()
25 # connection_ready 的第一個參數爲 sock,即 socket 的返回值
26 callback = functools.partial(connection_ready, sock)
27 # 註冊函數,第一個參數是將 sock 轉換爲標準的描述符,第二個爲回調函數,第三個是事件類型
28 io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
29 io_loop.start()

可以看到在註釋前都是使用了傳統的創建服務器的方式,不用多介紹,注意就是把套接口設置爲非阻塞方式。

創建ioloop實例,這裏是使用了ioloop.IOLoop中的 instance()靜態方法,以 @classmethod 方式包裝。

在後面的add_handler中,程序爲我們的監聽套接口註冊了一個回調函數和一個事件類型。工作方式是這樣,在註冊了相應的事件類型和回調函數以後,程序開始啓動,如果在相應的套接口上有事件發生(註冊的事件類型)那麼調用相應的回調函數。

當監聽套接口有可讀事件發生,意味着來了一個新連接,在回調函數中就可以對這個套接口accept,並調用相應的處理函數,其實應該是處理函數也設置爲異步的,將相應的連接套接口也加入到事件循環並註冊相應的回調函數,只是這裏沒有展示出來。

在使用非阻塞方式的accept時候常常返回EAGAIN,EWOULDBLOCK 錯誤,這裏採取的方式是放棄這個連接。

發佈了13 篇原創文章 · 獲贊 7 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章