服務器,事件
多進程單線程模型典型代表:nginx
單進程多線程模型典型代表:memcached
另外redis, mongodb也可以說是走的“多進程單線程模”模型(集羣),只不過作爲數據庫服務器,需要進行寫保護,只提供了讀同步。
原因很簡單,因爲服務器的發展大部分都是歸功於Linux Unix,而不是Windows。
Linux內核提供的epoll爲開發服務器提供了很大的便利,libevent和libev都是對epoll的封裝,nginx自己實現了對epoll的封裝。
libevent和libev都是知名的Linux系統C事件驅動編程框架。
我沒說錯的話,nodejs是建立在libev基礎上。
memcached也依賴libevent。
所以,nginx在Windows上不像Linux快是有很大原因的。
模型,模型,多進程單線程 單進程多線程
-
多進程單線程
master進程管理worker進程:
- 接收來自外界的信號
- 向各worker進程發送信號
- 監控woker進程的運行狀態
- 當woker進程退出後(異常情況下),會自動重新啓動新的woker進程
友情提示:nodejs屬於這一種好不好,不是隻能單核
-
單進程多線程
主線程負責監聽客戶端的連接請求,workers線程負責處理已經建立好的連接的讀寫等事件
單進程多線程肯定比多進程單線程快一些
多進程單線程與單進程多線程的目的都是想儘可能的利用CPU,減少CPU的空閒時間,特別是多核環境。
他們在實際運行中,所利用的CPU工作數應該都是相同的。也就是說,你有4核,在某個時刻要麼是CPU同時在4個進程做任務(多進程單線程),要麼是CPU同時在4個線程上做任務(單進程多線程)。
不過,單進程多線程肯定比多進程單線程快一些。
這是因爲,多進程單線程的CPU切換,是從一個進程到另一個進程,而單進程多線程的CPU切換則只在一個進程內,每個進程|線程都有自己的上下文堆棧保存,進程間的切換消耗更大一些。
這就好比是,多進程單線程是在4個函數中切換,各自擁有自己的變量;單進程多線程在1個函數中的4個子函數切換,擁有相同的全局變量。
但是,沒有你想象的“快幾倍”。
副作用,副作用,單進程多線程肯定有其不利的一面
我一直提過副作用。
如果你仔細看多進程單線程的圖,就應該明白,這種模型提供了一種保護機制。
當其中一個進程內部讀取錯誤,master可以讓ta重啓。這使得你的服務器在表面上並沒有感到“曾經崩潰”。
對於master,完全不涉及服務器的業務,使得ta能被安全隔離。
再來看單進程多線程。
問題很明顯,只有一個進程,一旦其中出現一個錯誤,整個進程都有可能掛掉。你當然可以爲ta編寫一個“守護程序”來重啓,但是重啓期間,你的服務器是真的“掛掉了”。
另外,編寫單進程多線程這樣的服務器,在代碼上非常容易出錯,而且難以控制代碼的穩定性,有很多你難以琢磨的bug在等着你,因爲有太多的鎖,太多的全局變量需要處理,這也是函數式“純函數”所反對的。
nodejs不能CPU密集處理?
你覺得ruby,python,php就能密集處理?
有人說:java, c#。
拜託,如果你真的想要密集處理,請使用C C++。(我個人只會用C)你見過哪個數據庫服務器是java c#寫的?
而現在,我覺得Rust lang是一個好的方向:
- 面向操作系統編程
- 從語言層面上提供併發
- 自詡C++的替代者
- 將會重寫firefox
- Mozilla開發
- Javascript的作者Brendan Eich是編寫者之一
- 類似javascript的語法和編寫體驗
而且我已經開始憧憬未來使用nodejs + Rust開發服務器體驗的場景。
原文鏈接:http://www.jianshu.com/p/c61a7746d139