如何選擇一個適合自己的開源項目來閱讀
人們都說, 閱讀源碼是提高編程水平的一個極好的方法, 但是如何找到一個適合自己閱讀的源碼, 就蛋疼的很. 優(yōu)秀的開源項目非常多, 肯定是看不完的. 而且如果沒有一個明確的目的, 只是因為火就看, 則事倍功半.
我更像一個后臺開發(fā)程序員, 所以以下觀點都基于后臺程序員的視角出發(fā).
從 Node.js 和 Tornado 出發(fā)
在幾個月前, 我學(xué)習(xí)了 Tornado 框架并用來做了一個項目; 而 Node.js 則是最近幾天才開始學(xué)的. 所以很可能會有說的不嚴謹?shù)牡胤?
Tornado 是一個 異步非阻塞服務(wù)器應(yīng)用 與輕量級 Web框架 的結(jié)合體. Node.js 則是一個開源跨平臺的 運行環(huán)境 (runtime environment). 在我看來, Node.js 基本上就是一個服務(wù)器應(yīng)用了, 因為這一部分和 Tornado 的服務(wù)器部分幾乎是一模一樣.
我們的問題主要是應(yīng)該選擇什么樣的開源代碼來閱讀, 目前為止, 我們可以選擇的項目有 Tornado 和 Node.js 了. 先不著急做出決定, 繼續(xù)向深處探索一番. 首先化簡問題, 因為 Node.js 的優(yōu)勢并非僅僅是異步非阻塞提供的高性能, 還有很多其他的東西, 我們暫時不管那些其他的部分.
- Tornado = AIO Server + Web Framework
- Node.js = AIO Server
如果學(xué)習(xí)過操作系統(tǒng), 就會知道 Linux 下這兩個程序之所以達到如此高性能的效果, 歸功于 Linux 2.6 Kernel 提供的 epoll . 我的思路是, Node.js 如果在 Linux 下運行, 一定會調(diào)用操作系統(tǒng)提供的 epoll; 如果在 Windows 下運行, 一定會調(diào)用操作系統(tǒng)提供的 IOCP .
順著這個思路, 我發(fā)現(xiàn)了 libuv 和 pyuv 這兩個開源項目.
- libuv : 一般認為, libuv 是因 nodejs 而生. libuv的作用是對用戶隱藏操作系統(tǒng)的差異, 封裝Linux的 libev 和 windows 的 IOCP 等等, 提供跨平臺的異步操作庫.
- pyuv : 給 Python 提供一個調(diào)用 libuv 的接口
屢清關(guān)系
上面提到了nodejs, tornado, libuv, pyuv, libev, IOCP 這些概念(項目), 他們中大部分都可以找到開源代碼, 如果想要從中選擇出合適自己學(xué)習(xí)的項目, 最好的辦法是先縷清他們的關(guān)系.
首先, Tornado 和 node.js 都可以用來做網(wǎng)站后臺服務(wù)器應(yīng)用. 而 Tornado 更是提供了一個 Web 框架.
Tornado 的 Web 框架提供了視圖和路由功能, 利用這一點我們可以很容易寫出一個 MVC 模式的 Web 應(yīng)用. 對于Web框架來說, 他直接從服務(wù)器應(yīng)用拿到用戶的 request, 處理完畢后得到一個 response, 直接給回服務(wù)器就可以了, 是不需要了解 request 如何傳輸過來以及 response 如何返回給用戶的細節(jié)的.
由于同時會有很多客戶端向服務(wù)器發(fā)起請求, 服務(wù)器要盡快處理這些請求, 提高性能一般是 讓cpu在單位時間里面盡量可以處理更多的I/O請求 , 方法一般就是采用阻塞的多線程, 或者非阻塞的單線程(當然也可以多線程或者多進程).
無論是采用哪一種I/O模型, 都要有操作系統(tǒng)的支持, 如果CPU沒有中斷功能, 操作系統(tǒng)就沒有鎖的功能, 也就沒有信號量, 沒有Monitor等一系列同步機制.
對于 Tornado 來說, Python 解釋器提供了上述一系列的同步機制. 因此 Tornado 到底能用什么樣的 I/O 模型, 直接取決于 Python 解釋器.
而 Python 解釋器是運行在操作系統(tǒng)之上, 如果操作系統(tǒng)不提供鎖, 那么解釋器也無法做出一把鎖. 因此 Tornado 到底能用什么樣的 I/O 模型, 間接取決于操作系統(tǒng).
我想 Node.js 也是一樣的道理.
得出結(jié)論
- 如果想知道一個網(wǎng)站的框架是如何將 路由 , 視圖(html, css, js之類) , 數(shù)據(jù)處理 拼在一起的, 那么可以閱讀 Tornado 源碼中的 Web 框架部分.
- 如果想知道同時有很多很多的 request 到來, 服務(wù)器應(yīng)用是如何利用操作系統(tǒng)提供的接口來完成 高并發(fā) 處理的, 可以閱讀 Tornado 的服務(wù)器部分或者 Node.js的源碼
- 如果想知道, 不同的操作系統(tǒng)提供了不同的接口, 如何在這個基礎(chǔ)上構(gòu)建出一個 跨平臺的統(tǒng)一接口 , 可以閱讀 libuv 的源碼
- 如果想知道在 Linux 操作系統(tǒng)下, 到底是如何 實現(xiàn)這些I/O接口 的, 可以閱讀 libev 的源碼
- 如果想知道如何利用 libuv, 在 Python 下也可以調(diào)用跨平臺 I/O 接口, 可以閱讀 pyuv 的源碼
不僅如此, 我們由結(jié)論還可以知道更多: 如果想看 libuv 的源碼, 知道 libuv 是如何實現(xiàn)的, 首先得會用它. 只有知道它的作用, 看起源碼來才有一個目的性. 要想知道如何使用 libuv, 得參考其上面一層的 Tornado 源碼中的很小一部分, 或者查閱 libuv 的文檔.
選擇源碼的一般方法
- 列出一些感興趣的關(guān)鍵字
- 對關(guān)鍵字的上層和下層進行了解
- 梳理出整個關(guān)系圖
- 得出結(jié)論, 做出選擇
經(jīng)過剛剛幾個步驟, 我們由對 Tornado 和 Node.js 的一些模糊的認識, 逐漸梳理出從用戶發(fā)起請求, 到操作系統(tǒng)甚至硬件層面的一條比較清晰的路線. 雖然一行源碼都還沒看, 已經(jīng)知道了我們看不同的源碼, 分別能學(xué)到什么知識. 在這個基礎(chǔ)上, 選擇適合自己當前需求的源碼來閱讀, 就能事半功倍了