Node.js機(jī)制及原理理解初步

一、node.js優(yōu)缺點(diǎn)

node.js是單線程。

好處就是

1)簡(jiǎn)單

2)高性能,避免了頻繁的線程切換開銷

3)占用資源小,因?yàn)槭菃尉€程,在大負(fù)荷情況下,對(duì)內(nèi)存占用仍然很低

3)線程安全,沒(méi)有加鎖、解鎖、死鎖這些問(wèn)題

壞處就是
  新、人少
  中間件少
  IDE不完善

PHP:


NODE.JS:


如何解決高并發(fā)?

node使用異步IO和事件驅(qū)動(dòng)(回調(diào)函數(shù))來(lái)解決這個(gè)問(wèn)題。
一般來(lái)說(shuō),高并發(fā)解決方案會(huì)提供多線程模型,為每個(gè)業(yè)務(wù)邏輯提供一個(gè)線程,通過(guò)[系統(tǒng)]線程切換來(lái)來(lái)彌補(bǔ)同步I/O調(diào)用的時(shí)間開銷。像apache,是一個(gè)請(qǐng)求一個(gè)線程。
而node.js使用的是單線程模型,對(duì)所有I/O都采用異步的請(qǐng)求方式,避免頻繁的上下文切換,在node.js執(zhí)行的時(shí)候維護(hù)著一個(gè)事件隊(duì)列;程序在執(zhí)行時(shí)進(jìn)入事件循環(huán)等待下一個(gè)事件到來(lái),每個(gè)異步I/O請(qǐng)求完成后都會(huì)被推送到事件隊(duì)列中的等待執(zhí)行。
比如說(shuō):
對(duì)于一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)訪問(wèn)操作,傳統(tǒng)方式是這樣實(shí)現(xiàn)的

res = db.query('SELECT * from some_table');  
res.output();  

代碼執(zhí)行到第一行的時(shí)候線程會(huì)阻塞,等待query返回結(jié)果,然后繼續(xù)處理。由于數(shù)據(jù)庫(kù)查詢、磁盤讀寫、網(wǎng)絡(luò)通信等原因(所謂的I/O)阻塞時(shí)間會(huì)非常大(相對(duì)于CPU始終頻率)。對(duì)于高并發(fā)的訪問(wèn),一方面線程長(zhǎng)期阻塞等待,另一方面為了應(yīng)付新情求而不斷添加新線程,會(huì)浪費(fèi)大量系統(tǒng)資源,同時(shí)線程的增加也會(huì)也會(huì)占用大量的CPU時(shí)間來(lái)處理內(nèi)存上下文切換??纯磏ode.js怎么處理

db.query('SELECT * from some_table', function(res) {   
   res.output();  
});  

query的第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),進(jìn)程執(zhí)行到db.query的時(shí)候不會(huì)等待結(jié)果返回,而是直接繼續(xù)執(zhí)行下面的語(yǔ)句,直到進(jìn)入事件循環(huán)。當(dāng)數(shù)據(jù)庫(kù)執(zhí)行結(jié)果返回的時(shí)候會(huì)將事件發(fā)送到事件隊(duì)列,等到線程進(jìn)入事件循環(huán)后才會(huì)調(diào)用之前的回調(diào)函數(shù)。

node.js的異步機(jī)制是基于事件的,所有的I/O、網(wǎng)絡(luò)通信、數(shù)據(jù)庫(kù)查詢都以非阻塞的方式執(zhí)行,返回結(jié)果由事件循環(huán)來(lái)處理。node.js在同一時(shí)刻只會(huì)處理一個(gè)事件,完成后立即進(jìn)入事件循環(huán)檢查后面事件。這樣CPU和內(nèi)存在同一時(shí)間集中處理一件事,同時(shí)盡量讓耗時(shí)的I/O等操作并行執(zhí)行。

事件循環(huán)機(jī)制

所謂事件循環(huán)是指node.js會(huì)把所有的異步操作使用事件機(jī)制解決,有個(gè)線程在不斷地循環(huán)檢測(cè)事件隊(duì)列。
node.js中所有的邏輯都是事件的回調(diào)函數(shù),所以node.js始終在事件循環(huán)中,程序入口就是事件循環(huán)第一個(gè)事件的回調(diào)函數(shù)。事件的回調(diào)函數(shù)中可能會(huì)發(fā)出I/O請(qǐng)求或直接發(fā)射( emit)事件,執(zhí)行完畢后返回事件循環(huán)。事件循環(huán)會(huì)檢查事件隊(duì)列中有沒(méi)有未處理的事件,直到程序結(jié)束。node.js的事件循環(huán)對(duì)開發(fā)者不可見,由libev庫(kù)實(shí)現(xiàn),libev不斷檢查是否有活動(dòng)的、可供檢測(cè)的事件監(jiān)聽器,直到檢查不到時(shí)才退出事件循環(huán),程序結(jié)束。

如圖所示


libuv 是一個(gè)高性能事件驅(qū)動(dòng)的程序庫(kù),封裝了 Windows 和 Unix 平臺(tái)一些底層特性,為開發(fā)者提供了統(tǒng)一的 API.
因此,node.js 是單線程,異步非阻塞。
但畢竟,如何彌補(bǔ)單線程缺陷?是不是有異步非阻塞,就可以高枕無(wú)憂了?
不是的。

1)CPU密集型任務(wù)存在短板

如上所述,nodejs的機(jī)制是單線程,這個(gè)線程里面,有一個(gè)事件循環(huán)機(jī)制,處理所有的請(qǐng)求。如圖所示。在事件處理過(guò)程中,它會(huì)智能地將一些涉及到IO、網(wǎng)絡(luò)通信等耗時(shí)比較長(zhǎng)的操作,交由worker threads去執(zhí)行,執(zhí)行完了再回調(diào),這就是所謂的異步IO非阻塞吧。但是,那些非IO操作,只用CPU計(jì)算的操作,它就自己扛了,比如算什么斐波那契數(shù)列之類。它是單線程,這些自己扛的任務(wù)要一個(gè)接著一個(gè)地完成,前面那個(gè)沒(méi)完成,后面的只能干等。因此,對(duì)CPU要求比較高的CPU密集型任務(wù)多的話,就有可能會(huì)造成號(hào)稱高性能,適合高并發(fā)的node.js服務(wù)器反應(yīng)緩慢。

2)無(wú)法利用CPU的多核
最開始,線程只是用于分配單個(gè)處理器處理時(shí)間的一種機(jī)制。但假如操作系統(tǒng)本身支持多個(gè)CPU/內(nèi)核,那么每個(gè)線程都可以得到一個(gè)不同自己的CPU/內(nèi)核,實(shí)現(xiàn)真正的“并行運(yùn)算”。在這種情況下,多線程程序可以提高資源使用效率。Node.js是單線程程序,它只有一個(gè)event loop,也只占用一個(gè)CPU/內(nèi)核。現(xiàn)在大部分服務(wù)器都是多CPU或多核的,當(dāng)Node.js程序的event loop被CPU密集型的任務(wù)占用,導(dǎo)致有其它任務(wù)被阻塞時(shí),卻還有CPU/內(nèi)核處于閑置的狀態(tài),造成資源的浪費(fèi)。

解決方案
利用原生模塊或第三方模塊,開辟進(jìn)程或子進(jìn)程,用于處理這些特殊的任務(wù)。
3)如果有異常拋出,因?yàn)槭菃尉€程,整個(gè)項(xiàng)目將不可用。但這歸根到底是代碼的問(wèn)題,糟糕的代碼,不管什么體系,都會(huì)有問(wèn)題,即使不崩潰。解決辦法是用pm2等工具來(lái)運(yùn)行?

二、nodejs與javascript的關(guān)系

nodejs本身不是開發(fā)語(yǔ)言,它是一個(gè)工具或者平臺(tái),在服務(wù)器端解釋、運(yùn)行javascript;coffeescript屬于nodejs體系,算是一種新的開發(fā)語(yǔ)言,但它的目的在于最后編譯成javascript。
nodejs利用Google V8來(lái)解釋運(yùn)行javascript,但是系統(tǒng)真正執(zhí)行的代碼是用C++寫的。javascript做的只是調(diào)用這些API而已。因此,并無(wú)執(zhí)行效率的問(wèn)題。

三、nodejs適用場(chǎng)景

1、RESTful API
這是適合 Node 的理想情況,因?yàn)槟梢詷?gòu)建它來(lái)處理數(shù)萬(wàn)條連接。它仍然不需要大量邏輯;它本質(zhì)上只是從某個(gè)數(shù)據(jù)庫(kù)中查找一些值并將它們組成一個(gè)響應(yīng)。由于響應(yīng)是少量文本,入站請(qǐng)求也是少量的文本,因此流量不高,一臺(tái)機(jī)器甚至也可以處理最繁忙的公司的 API 需求。
2、實(shí)時(shí)程序
比如聊天服務(wù)
聊天應(yīng)用程序是最能體現(xiàn) Node.js 優(yōu)點(diǎn)的例子:輕量級(jí)、高流量并且能良好的應(yīng)對(duì)跨平臺(tái)設(shè)備上運(yùn)行密集型數(shù)據(jù)(雖然計(jì)算能力低)。同時(shí),聊天也是一個(gè)非常值得學(xué)習(xí)的用例,因?yàn)樗芎?jiǎn)單,并且涵蓋了目前為止一個(gè)典型的 Node.js 會(huì)用到的大部分解決方案。
3、單頁(yè)APP
ajax很多。現(xiàn)在單頁(yè)的機(jī)制似乎很流行,比如phonegap做出來(lái)的APP,一個(gè)頁(yè)面包打天下的例子比比皆是。
總而言之,NodeJS適合運(yùn)用在高并發(fā)、I/O密集、少量業(yè)務(wù)邏輯的場(chǎng)景

轉(zhuǎn)自https://www.2cto.com/uploadfile/Collfiles/20141217/20141217085608233.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 總結(jié)一: [node.js總結(jié)](http://www.cnblogs.com/Darren_code/archi...
    xiumeiii閱讀 2,010評(píng)論 0 14
  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宮若石閱讀 1,228評(píng)論 0 1
  • 這是一個(gè)移動(dòng)端工程師涉足前端和后端開發(fā)的學(xué)習(xí)筆記,如有錯(cuò)誤或理解不到位的地方,萬(wàn)望指正。 Node.js 是什么 ...
    單純的土豆閱讀 1,362評(píng)論 2 17
  • 設(shè)計(jì)高性能Web服務(wù)器的要點(diǎn)在于非阻塞I/O和事件驅(qū)動(dòng) Node最大的特點(diǎn)是異步式I/O(非阻塞I/O)與事件緊密...
    JunChow520閱讀 2,129評(píng)論 0 0
  • 我親愛(ài)的表哥,你今年30歲了,我不知道要用什么樣的禮物,才能彰顯你的珍貴,我的用心。 為了給你送禮物這件事,我請(qǐng)教...
    無(wú)味丸子閱讀 905評(píng)論 0 0

友情鏈接更多精彩內(nèi)容