Python伺服器編程
IEEE公布的2017年編程語言排行榜,python高居首位。在百度指數上,python的搜索量也躋身到與java相等的量級,成為最火的語言之一。
那麼Python適合用來做伺服器編程嗎?
首先,看看哪些公司在用Python作為伺服器的主要技術棧?可以看到,其中不缺乏一些用戶量龐大的公司。
得益於語言的簡潔性,python很適合用來進行快速開發,編寫出可讀性強的程序。那麼怎麼用python來做伺服器編程呢?
從一個例子說起...
這是一個簡單的回顯伺服器,服務端每次從請求讀取一些位元組並返回給客戶端。
但由於伺服器是單進程的,如果一個請求佔住了伺服器,就沒辦法處理另一個請求。
這次做一些改動,每來一個請求就fork一個進程來處理,這樣就不會出現之前的問題。
但多進程模型處理不好會出現殭屍進程和孤兒進程,因此父進程需要處理SIGCHILD信號來收集退出的子進程的信息。
socketserver模塊中ForkingMixIn收集子進程的例子:
原始的CGI程序就是使用這種方式,對於每個請求都fork進程來解釋cgi程序。
不過隨著請求數量的變多,fork進程所帶來的開銷往往很大。
所以CGI不僅慢...
而且
甚至
後來出現了FastCGI,它與CGI的區別,就是更Fast(誤),它是一個常駐進程,預先啟動多個cgi進程來等待處理請求。
不同於FastCGI,Apache搞了一套mod_python,使得python解釋器可以嵌入在apache進程。
後來PEP 333中定義了WSGI,成為沿用至今的Python web開發的標準協議。
應用WSGI協議的一個示例:
絕大部分的python web開發框架都遵守了這套標準:
gunicorn是一個著名的wsgi http伺服器,它採用pre-fork模型來處理和轉發請求。(原圖出處)
gunicorn包含許多種worker模型:(原圖出處)
拋開多進程,現在來看多線程的模型,該方案用線程代替進程來處理每一個請求:
但是為什麼許多人說python的多線程是個雞肋呢?看下面同樣的代碼,用同步的方式和多線程的方式執行,多線程的代碼卻執行的更慢...
這到底是什麼回事?
這就要說到python中的GIL了,由於GIL的制約,多線程很難充分利用cpu的性能(原圖引用)
話雖如此,多線程在IO密集型應用上還是有不少用武之地的。下面是多線程在伺服器編程的其中一些應用(原圖引用)
Actor模型
生產者-消費者
concurrent.future在PEP 3148中被定義,它提供了更簡單的多進程/多線程API
在很長的一段時間,多進程/多線程的模型都應用的很好,但是
這時候更適合伺服器編程的IO多路復用模型開始被廣泛應用:
基於事件驅動的非同步模型對伺服器的資源的有效利用率顯然易見(原圖出處)
衍生了大量的非同步網路框架
在Python 3.4後出現了專門處理非同步IO的標準庫asyncio
而在隨後的Python 3.5後出現了協程語法糖async/await
雖然asyncio成為標準庫,但它使用方法卻較為複雜,不便於使用,也有人提議要asyncio提供更簡潔的介面,也有不少的替代庫出現
總的來說,伺服器編程經歷了從開始的簡單到後來的複雜化最終慢慢演變到簡單的方式上。
PS:部分代碼和幻燈中的圖片是從網上找的,原出處不明,侵刪請告知
推薦閱讀:
※如何真正零基礎入門Python?(第二節)
※【乾貨】關於如何入門/學習xxx(下)
※畢竟是一個看顏值的世界——Python實現從Excel讀取數據並繪製成精美圖像
※Web開發必備工具箱
※我們採訪了劍橋學生會主席,關於少兒編程他這麼說