1. 程式人生 > >深入理解非同步Web伺服器 Tornado

深入理解非同步Web伺服器 Tornado

這篇文章的目的在於對Tornado這個非同步伺服器軟體的底層進行一番探索。我採用自底向上的方式進行介紹,從輪訓開始,向上一直到應用層,指出我認為有趣的部分。

所以,如果你有打算要閱讀Tornado這個web框架的原始碼,又或者是你對一個非同步web伺服器是如何工作的感興趣,我可以在這成為你的指導。

通過閱讀這篇文章,你將可以:

  • 自己寫一個Comet架構程式的伺服器端部分,即使你是從拷貝別人的程式碼開始。
  • 如果你想在Tornado框架上做開發,通過這篇文章你將更好的理解Tornado web框架。

介紹

假設你還不知道Tornado是什麼也不知道為什麼應該對它感興趣,那我將用簡短的話來介紹Tornado這個專案。如果你已經對它有了興趣,你可以跳去看下一節內容。

Tornado是一個用Python編寫的非同步HTTP伺服器,同時也是一個web開發框架。該框架服務於FriendFeed網站,最近Facebook也在使用它。FriendFeed網站有使用者數多和應用實時性強的特點,所以效能和可擴充套件性是很受重視的。由於現在它是開源的了(這得歸功於Facebook),我們可以徹底的對它是如何工作的一探究竟。

我覺得對非阻塞式IO (nonblocking IO) 和非同步IO (asynchronous IO  AIO)很有必要談一談。如果你已經完全知道他們是什麼了,可以跳去看下一節。我儘可能的使用一些例子來說明它們是什麼。

讓我們假設你正在寫一個需要請求一些來自其他伺服器上的資料(比如資料庫服務,再比如新浪微博的open api)的應用程式,然後呢這些請求將花費一個比較長的時間,假設需要花費5秒鐘。大多數的web開發框架中處理請求的程式碼大概長這樣:

Python
123defhandler_request(self,request):answ=self.remote_server.query(request)# this takes 5 secondsrequest.write_response(answ)

如果這些程式碼執行在單個執行緒中,你的伺服器只能每5秒接收一個客戶端的請求。在這5秒鐘的時間裡,伺服器不能幹其他任何事情,所以,你的服務效率是每秒0.2個請求,哦,這太糟糕了。

當然,沒人那麼天真,大部分伺服器會使用多執行緒技術來讓伺服器一次接收多個客戶端的請求,我們假設你有20個執行緒,你將在效能上獲得20倍的提高,所以現在你的伺服器效率是每秒接受4個請求,但這還是太低了,當然,你可以通過不斷地提高執行緒的數量來解決這個問題,但是,執行緒在記憶體和排程方面的開銷是昂貴的,我懷疑如果你使用這種提高執行緒數量的方式將永遠不可能達到每秒100個請求的效率。

如果使用AIO,達到每秒上千個請求的效率是非常輕鬆的事情。伺服器請求處理的程式碼將被改成這樣:

AIO的思想是當我們在等待結果的時候不阻塞,轉而我們給框架一個回撥函式作為引數,讓框架在有結果的時候通過回撥函式通知我們。這樣,伺服器就可以被解放去接受其他客戶端的請求了。

然而這也是AIO不太好的地方:程式碼有點不直觀了。還有,如果你使用像Tornado這樣的單執行緒AIO伺服器軟體,你需要時刻小心不要去阻塞什麼,因為所有本該在當前返回的請求都會像上述處理那樣被延遲返回。

關於非同步IO,比當前這篇過分簡單的介紹更好的學習資料請看 The C10K problem

原始碼

該專案由github託管,你可以通過如下命令獲得,雖然通過閱讀這篇文章你也可以不需要它是吧。

Shell
1 git clonegit://github.com/facebook/tornado.git

在tornado的子目錄中,每個模組都應該有一個.py檔案,你可以通過檢查他們來判斷你是否從已經從程式碼倉庫中完整的遷出了專案。在每個原始碼的檔案中,你都可以發現至少一個大段落的用來解釋該模組的doc string,doc string中給出了一到兩個關於如何使用該模組的例子。

IOLoop模組

讓我們通過檢視ioloop.py檔案直接進入伺服器的核心。這個模組是非同步機制的核心。它包含了一系列已經開啟的檔案描述符(譯者:也就是檔案指標)和每個描述符的處理器(handlers)。它的功能是選擇那些已經準備好讀寫的檔案描述符,然後呼叫它們各自的處理器(一種IO多路複用的實現,其實就是socket眾多IO模型中的select模型,在Java中就是NIO,譯者注)。

可以通過呼叫add_handler()方法將一個socket加入IO迴圈中:

Python
1234defadd_handler(self,fd,handler,events):"""Registers the given handler to receive the given events for fd."""self._handlers[fd]=handlerself._impl.register(fd,events|self.ERROR)

_handlers這個字典型別的變數儲存著檔案描述符(其實就是socket,譯者注)到當該檔案描述符準備好時需要呼叫的方法的對映(在Tornado中,該方法被稱為處理器)。然後,檔案描述符被註冊到epoll(unix中的一種IO輪詢機制,貌似,譯者注)列表中。Tornado關心三種類型的事件(指發生在檔案描述上的事件,譯者注):READ,WRITE 和 ERROR。正如你所見,ERROR是預設為你自動新增的。

self._impl是select.epoll()selet.select()兩者中的一個。我們稍後將看到Tornado是如何在它們之間進行選擇的。

現在讓我們來看看實際的主迴圈,不知何故,這段程式碼被放在了start()方法中:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

相關推薦

深入理解非同步Web伺服器 Tornado

這篇文章的目的在於對Tornado這個非同步伺服器軟體的底層進行一番探索。我採用自底向上的方式進行介紹,從輪訓開始,向上一直到應用層,指出我認為有趣的部分。 所以,如果你有打算要閱讀Tornado這個web框架的原始碼,又或者是你對一個非同步web伺服器是如何工

java深入理解---非同步回撥機制例項解析

一、什麼是回撥 回撥,回撥。要先有呼叫,才有呼叫者和被呼叫者之間的回撥。所以在百度百科中是這樣的: 軟體模組之間總是存在著一定的介面,從呼叫方式上,可以把他們分為三類:同步呼叫、回撥和非同步呼叫。 回撥是一種特殊的呼叫,至於三種方式也有點不同。 1、同步回撥,

python寫簡單的web靜態伺服器,對socket的深入理解

import socket from multiprocessing import Process import time #...使用socket建立簡單的靜態伺服器 def func1(sock): # 子程序實現的功能 read_data = sock.recv(2

深入理解javascript非同步程式設計障眼法&&h5 web worker實現多執行緒

0.從一道題說起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 問,以上程式碼何時alert“end”呢? 測試一下:答案是:

深入剖析 Web 伺服器與 PHP 應用之間的通訊機制 - 掌握 CGI 和 FastCGI 協議的執行原理

本文首發於 深入剖析 Web 伺服器與 PHP 應用之間的通訊機制 - 掌握 CGI 和 FastCGI 協議的執行原理,轉載請註明出處! 身為一名使用 PHP 語言開發後端服務的程式猿,我們每天都和 PHP 以及 Web 伺服器產生無數次的親密接觸。得益於它們,我們才能

C# async/await非同步變成深入理解

非同步函式簡介 一般指 async 修飾符宣告得、可包含await表示式得方法或匿名函式。   宣告方式 非同步方法的宣告語法與其他方法完全一樣, 只是需要包含 async 關鍵字。async可以出現在返回值之前的任何位置, 如下示例: async public st

tornado非同步web請求

1.為什麼要使用非同步web服務 使用非同步非阻塞請求,併發處理更高效。 2.同步與非同步請求比較 同步請求時,web伺服器程序是阻塞的,也就是說當一個請求被處理時,伺服器程序會被掛起直至請求完成。 非同步請求時,web伺服器程序在等待請求處理過程中,讓I/O迴圈開啟,以便服務於其他請求,請

深入理解tornado的ioloop

本文所剖析的tornado原始碼版本為4.4.2 ioloop是tornado的關鍵,是他的最底層。 ioloop就是對I/O多路複用的封裝,它實現了一個單例,將這個單例儲存在IOLoop._instance中 ioloop實現了Reactor模型,將所有要處理的I/O事件註冊

web深入理解負載均衡 2018-10-5

深入理解負載均衡 負載均衡 負載均衡是高可用架構的一個關鍵元件,主要用來提高效能和可用性,通過負載均衡將流量分發到多個伺服器,同時多伺服器能夠消除這部分的單點故障。 當然負載均衡器本身就是一個單點故障隱患,可以考慮文章後面說的負載均衡雙機熱備或其他方案消除單點

深入理解ES6》——Promise非同步程式設計

Promise的生命週期     每個promise都會經歷一個短暫的生命週期:先是處於進行中(pending)的狀態,此時操作尚未完成,所以它也是未處理(unsettled)的;一旦非同步操作執行結束,Promise則變為已處理(settled)的狀態。已處理的狀態又分為

Web 服務】深入理解無狀態協議、HTTP 與 web 會話

1. 什麼是狀態(state)? 狀態可以簡單地理解為事物在某一個時間點上的特徵表現。事物在不斷的發展、運動和變化,這樣才會有狀態,這樣的狀態才會有意義!絕對的靜止就是黑洞,就不會有狀態,也不會產生資訊! 生老病死,花開花謝,春去秋來,都是事物狀態的變遷!

web伺服器、Apache 和 tomcat 關係的理解

以一次JSP請求響應為例,講解伺服器,Apache、Tomcat之間的關係。 帶著這樣一個概念去看:Apache與Apache Tomcat(簡稱Tomcat)都是可以獨立執行的伺服器。你平時見到的apache-tomcat-7.0.72實際上只是Tomcat伺服器。此處整

深入理解web.xml中配置/和/*的區別

 在用SpringMVC進行web開發的時候,如果將DispathcerServlet對外訪問的虛擬路徑配置成/時,需要在Spring的配置檔案中配置<mvc:default-servlet-handler/>這一項,那麼為什麼需要配置這一項呢?如果對外訪

深入理解併發/並行,阻塞/非阻塞,同步/非同步 同步與阻塞,非同步與非阻塞的區別

同步與非同步是對應的,它們是執行緒之間的關係,兩個執行緒之間要麼是同步的,要麼是非同步的。阻塞與非阻塞是對同一個執行緒來說的,在某個時刻,執行緒要麼處於阻塞,要麼處於非阻塞。阻塞是使用同步機制的結果,非阻塞則是使用非同步機制的結果。 深入理解併發/並行,阻塞/非阻塞,同步/非同步 1. 阻塞,非

web基礎】深入理解http和https的區別

在對比這兩者的區別之前咱們先來看一下http有哪些缺點 第一個缺點:http通訊使用明文可能會被竊聽。由於http本身不具備加密的功能,所以也無法做到對通訊整體(使用http協議通訊的請求和響應)的加密。也就是說http的報文使用的是明文傳送。 為什麼通訊不加密

這篇文章講得精彩-深入理解 Python 非同步程式設計(上)!

可惜,二和三現在還沒有出來~ ~~~~~~~~~~~~~~~~~~~~~~~~~ http://python.jobbole.com/88291/ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 在Python 3.3 引入yield from新語法之後,就不再推薦用yield去做協程。全都使

深入理解JavaScript的執行機制(同步和非同步

不論是面試求職,還是日常開發工作,我們經常會遇到這樣的情況:給定的幾行程式碼,我們需要知道其輸出內容和順序。因為JavaScript是一門單執行緒語言,所以我們可以得出結論: JavaScript是按照語句出現的順序執行的 所以我們以為JS都是這樣的:

深入理解併發/並行,阻塞/非阻塞,同步/非同步

1. 阻塞,非阻塞 首先,阻塞這個詞來自作業系統的執行緒/程序的狀態模型中,如下圖: 一個執行緒/程序經歷的5個狀態,建立,就緒,執行,阻塞,終止。各個狀態的轉換條件如上圖,其中有個阻塞狀態,就是說當執行緒中呼叫某個函式,需要IO請求,或者暫時得不到競爭

深入理解伺服器架構(Faas/Serverless)

摘要 無伺服器架構(Faas/Serverless),是軟體架構領域的熱門話題。 AWS,Google Cloud和Azure - 在無伺服器上投入了大量資金,已經在看到了大量專門針對Faas/Serverless的文章、書籍,開源專案,會議。 但什麼是無伺服

深入理解JS非同步程式設計五(指令碼非同步載入)

非同步指令碼載入 阻塞性指令碼 JavaScript在瀏覽器中被解析和執行時具有阻塞的特性,也就是說,當JavaScript程式碼執行時,頁面的解析、渲染以及其他資源的下載都要停下來等待指令碼執行完畢 瀏覽器是按照從上到下的順序解析頁面,因此正常情況下,J