Python 和Ruby 也有這樣的框架,但因為在實際使用中會不可避免地用到含有同步程式碼的函式庫,因此沒能成長起來,而在Node.js 之前,JavaScript 的伺服器端程式設計幾乎是空白,所以Node.js 才得以建立了一個所有IO 都是非同步的程式碼庫。
大部分 Web 應用的瓶頸都在 IO, 即讀寫磁碟,讀寫網絡,讀寫資料庫。使用怎樣的策略等待這段時間,就成了改善效能的關鍵點。
PHP 的策略:多進程運行,直接原地等待 IO 完成。缺點:多個進程會消耗多份內存,進程間難以共享資料。
C/C 通常的策略:多執行緒運行,程式自行維護鎖的狀態。缺點:開發成本高,容易出錯,不易調試。
Python(Tornado): 多個請求在單一進程中輪流執行,遇到 IO 時切換到另一個請求。缺點:對於單一請求而言,依然沒有最有效率地利用時間。
何謂「最有效率地利用時間」?例如現在有兩個不相關的資料庫查詢,在PHP 中通常會先執行一個,執行完成後再執行第二個(總時間是a b). 顯然這不是最有效率的,應該同時執行兩個查詢,時間是max(a, b).
Python 和其他支援多執行緒的語言的問題就在於,在語言層面,程式設計師很難告訴虛擬機,應當將兩個操作同時執行,即使有辦法,也相當麻煩,大多數人懶得去用(也不值得去用)。而因為Node.js 喪心病狂地強制所有IO 非同步執行,Node.js 的程式設計師也可以說是輕車熟路,配合一些改善程式碼可讀性函式庫(promise, async), 可以很輕鬆地讓不相干的操作並行執行。
上面講了非同步 IO 的實現,那麼非同步 IO 的優勢究竟體現在哪裡呢。實際上非同步 IO 並不能神奇地減輕伺服器的壓力,該加伺服器還是一樣要加伺服器,只不過異步 IO 會減少單一請求的時間,去掉單一請求中那些無意義的等待時間。所以單位時間內處理的請求沒有變化,但每個請求的處理時間都減少了。從這個角度,伺服器也節省了一些資源——也就是維持每個請求的連線消耗的記憶體。