一、Node.js優缺點
node.js是單線程。
好處就是
1)簡單
2)高性能,避免了頻繁的線程切換開銷
3)佔用資源小,因爲是單線程,在大負荷情況下,對內存佔用仍然很低
3)線程安全,沒有加鎖、解鎖、死鎖這些問題
php
node.js
壞處就是
如何解決高併發?
node使用異步IO和事件驅動(回調函數)來解決這個問題。
一般來說,高併發解決方案會提供多線程模型,爲每個業務邏輯提供一個線程,通過系統線程切換來來彌補同步I/O調用的時間開銷。像apache,是一個請求一個線程。
而node.js使用的是單線程模型,對所有I/O都採用異步的請求方式,避免頻繁的上下文切換,在node.js執行的時候維護着一個事件隊列;程序在執行時進入事件循環等待下一個事件到來,每個異步I/O請求完成後都會被推送到事件隊列中的等待執行。
比如說:
對於一個簡單的數據庫訪問操作,傳統方式是這樣實現的
代碼執行到第一行的時候線程會阻塞,等待query返回結果,然後繼續處理。由於數據庫查詢、磁盤讀寫、網絡通信等原因(所謂的I/O)阻塞時間會非常大(相對於CPU始終頻率)。對於高併發的訪問,一方面線程長期阻塞等待,另一方面爲了應付新情求而不斷添加新線程,會浪費大量系統資源,同時線程的增加也會也會佔用大量的CPU時間來處理內存上下文切換。看看node.js怎麼處理
query的第二個參數是一個回調函數,進程執行到db.query的時候不會等待結果返回,而是直接繼續執行下面的語句,直到進入事件循環。當數據庫執行結果返回的時候會將事件發送到事件隊列,等到線程進入事件循環後纔會調用之前的回調函數。
node.js的異步機制是基於事件的,所有的I/O、網絡通信、數據庫查詢都以非阻塞的方式執行,返回結果由事件循環來處理。node.js在同一時刻只會處理一個事件,完成後立即進入事件循環檢查後面事件。這樣CPU和內存在同一時間集中處理一件事,同時儘量讓耗時的I/O等操作並行執行。
事件循環機制
所謂事件循環是指node.js會把所有的異步操作使用事件機制解決,有個線程在不斷地循環檢測事件隊列。
node.js中所有的邏輯都是事件的回調函數,所以node.js始終在事件循環中,程序入口就是事件循環第一個事件的回調函數。事件的回調函數中可能會發出I/O請求或直接發射( emit)事件,執行完畢後返回事件循環。事件循環會檢查事件隊列中有沒有未處理的事件,直到程序結束。node.js的事件循環對開發者不可見,由libev庫實現,libev不斷檢查是否有活動的、可供檢測的事件監聽器,直到檢查不到時才退出事件循環,程序結束。
如圖所示
libuv 是一個高性能事件驅動的程序庫,封裝了 Windows 和 Unix 平臺一些底層特性,爲開發者提供了統一的 API.
因此,node.js 是單線程,異步非阻塞。
但畢竟,如何彌補單線程缺陷?是不是有異步非阻塞,就可以高枕無憂了?
不是的。
1)CPU密集型任務存在短板
如上所述,nodejs的機制是單線程,這個線程裏面,有一個事件循環機制,處理所有的請求。如圖所示。在事件處理過程中,它會智能地將一些涉及到IO、網絡通信等耗時比較長的操作,交由worker threads去執行,執行完了再回調,這就是所謂的異步IO非阻塞吧。但是,那些非IO操作,只用CPU計算的操作,它就自己扛了,比如算什麼斐波那契數列之類。它是單線程,這些自己扛的任務要一個接着一個地完成,前面那個沒完成,後面的只能乾等。因此,對CPU要求比較高的CPU密集型任務多的話,就有可能會造成號稱高性能,適合高併發的node.js服務器反應緩慢。
2)無法利用CPU的多核
最開始,線程只是用於分配單個處理器處理時間的一種機制。但假如操作系統本身支持多個CPU/內核,那麼每個線程都可以得到一個不同自己的CPU/內核,實現真正的“並行運算”。在這種情況下,多線程程序可以提高資源使用效率。Node.js是單線程程序,它只有一個event
loop,也只佔用一個CPU/內核。現在大部分服務器都是多CPU或多核的,當Node.js程序的event loop被CPU密集型的任務佔用,導致有其它任務被阻塞時,卻還有CPU/內核處於閒置的狀態,造成資源的浪費。
解決方案
利用原生模塊或第三方模塊,開闢進程或子進程,用於處理這些特殊的任務。
3)如果有異常拋出,因爲是單線程,整個項目將不可用。但這歸根到底是代碼的問題,糟糕的代碼,不管什麼體系,都會有問題,即使不崩潰。解決辦法是用pm2等工具來運行?
二、nodejs與JavaScript的關係
nodejs本身不是開發語言,它是一個工具或者平臺,在服務器端解釋、運行javascript;coffeescript屬於nodejs體系,算是一種新的開發語言,但它的目的在於最後編譯成javascript。
nodejs利用Google V8來解釋運行javascript,但是系統真正執行的代碼是用C++寫的。javascript做的只是調用這些API而已。因此,並無執行效率的問題。
三、nodejs適用場景
1、RESTful API
這是適合 Node 的理想情況,因爲您可以構建它來處理數萬條連接。它仍然不需要大量邏輯;它本質上只是從某個數據庫中查找一些值並將它們組成一個響應。由於響應是少量文本,入站請求也是少量的文本,因此流量不高,一臺機器甚至也可以處理最繁忙的公司的 API 需求。
2、實時程序
比如聊天服務
聊天應用程序是最能體現 Node.js 優點的例子:輕量級、高流量並且能良好的應對跨平臺設備上運行密集型數據(雖然計算能力低)。同時,聊天也是一個非常值得學習的用例,因爲它很簡單,並且涵蓋了目前爲止一個典型的 Node.js 會用到的大部分解決方案。
3、單頁APP
ajax很多。現在單頁的機制似乎很流行,比如phonegap做出來的APP,一個頁面包打天下的例子比比皆是。
。。。
總而言之,NodeJS適合運用在高併發、I/O密集、少量業務邏輯的場景
參考文章
http://www.slideshare.net/mysqlops/nodejs-9313477
http://www.ruanyifeng.com/blog/2014/10/event-loop.html