node高并發(fā)原理機制解讀
概念
- 1.事件循環(huán):
事件循環(huán)是一種編程構(gòu)造,用于等待和分派程序中的事件或消息, 主線程從"任務(wù)隊列"中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為Event Loop(事件循環(huán))
- 2.事件隊列:
當(dāng)用戶的網(wǎng)絡(luò)請求或者其它的異步操作到來時,node都會把它放到Event Queue之中,此時并不會立即執(zhí)行它,代碼也不會被阻塞,繼續(xù)往下走,直到主線程代碼執(zhí)行完畢。
- 3.任務(wù)隊列:
任務(wù)隊列"是一個事件的隊列(也可以理解成消息的隊列),IO設(shè)備完成一項任務(wù),就在"任務(wù)隊列"中添加一個事件,表示相關(guān)的異步任務(wù)可以進入"執(zhí)行棧"了。主線程讀取"任務(wù)隊列",就是讀取里面有哪些事件。
- 4.事件驅(qū)動:
實質(zhì)是通過主循環(huán)加事件觸發(fā)方式運行程序
- 5.node
Node.js 不是一門語言也不是框架,它只是基于 Google V8 引擎的 JavaScript 運行時環(huán)境,是對 js 功能的拓展。提供了網(wǎng)絡(luò)、文件、dns 解析、進程線程等功能。
- 6.libuv
libuv是專門為Node.js開發(fā)的一個封裝庫,提供跨平臺的異步I/O能力。
注:
1. 一個事件循環(huán)有一個或多個任務(wù)隊列。一個任務(wù)隊列是一組的任務(wù)
2. Libuv 主要是,利用系統(tǒng)提供的事件驅(qū)動模塊解決網(wǎng)絡(luò)異步 IO,利用線程池解決文件IO。另外還實現(xiàn)了定時器,對進程、線程等使用進行了封裝。
node架構(gòu)圖
Node Standard Library 標(biāo)準(zhǔn)庫,如Http, event模塊。
Node Bindings 是溝通JS 和 C++的橋梁,封裝V8和Libuv的細(xì)節(jié),向上層提供基礎(chǔ)API服務(wù)。由 C/C++ 實現(xiàn)。
V8 是Google開發(fā)的JavaScript引擎,提供JavaScript運行環(huán)境,可以說它就是 Node.js 的發(fā)動機。
Libuv 是專門為Node.js開發(fā)的一個封裝庫,提供跨平臺的異步I/O能力.
單線程、異步
單線程就意味著,所有任務(wù)需要排隊,前一個任務(wù)結(jié)束,才會執(zhí)行后一個任務(wù)。
如果前一個任務(wù)耗時很長,后一個任務(wù)就不得不一直等著。
node單線程指的是node在執(zhí)行程序代碼時,主線程是單線程。
異步體現(xiàn)在,主線程之外,還維護了一個"事件隊列"(Event queue)。
當(dāng)用戶的網(wǎng)絡(luò)請求或者其它的異步操作到來時,node都會把它放到Event Queue之中,此時并不會立即執(zhí)行它,代碼也不會被阻塞,繼續(xù)往下走,直到主線程代碼執(zhí)行完畢.
注:
- JavaScript 是單線程的,Node 本身其實是多線程的,只是 I/O 線程使用的 CPU 比較少;還有個重要的觀點是,除了用戶的代碼無法并行執(zhí)行外,所有的 I/O (磁盤 I/O 和網(wǎng)絡(luò) I/O) 則是可以并行起來的。
- libuv 線程池默認(rèn)打開 4 個,最多打開 128個 線程。
事件循環(huán)
Node 開始執(zhí)行腳本時,會先進行事件循環(huán)的初始化,但是這時事件循環(huán)還沒有開始,會先完成下面的事情。
- 同步任務(wù)
- 發(fā)出異步請求
- 規(guī)劃定時器生效的時間
- 執(zhí)行process.nextTick()等
然后就調(diào)用libuv事件循環(huán)階段,事件循環(huán)會無限次地執(zhí)行,一輪又一輪。
只有異步任務(wù)的回調(diào)函數(shù)隊列清空了,才會停止執(zhí)行。
Node中的事件循環(huán)有6個階段
event loop 的每個階段都有一個任務(wù)隊列
當(dāng) event loop 到達某個階段時,將執(zhí)行該階段的任務(wù)隊列,直到隊列清空或執(zhí)行的回調(diào)達到系統(tǒng)上限后,才會轉(zhuǎn)入下一個階段
當(dāng)所有階段被順序執(zhí)行一次后,稱 event loop 完成了一個 tick
注:
node中的事件循環(huán)與瀏覽器有區(qū)別~
事件驅(qū)動+事件循環(huán)實現(xiàn)高并發(fā)
具體執(zhí)行順序:
1、每個Node.js進程只有一個主線程在執(zhí)行程序代碼,形成一個執(zhí)行棧(execution context stack)
2、主線程之外,還維護了一個"事件隊列"(Event queue)。當(dāng)用戶的網(wǎng)絡(luò)請求或者其它的異步操作到來時,node都會把它放到Event Queue之中,此時并不會立即執(zhí)行它,代碼也不會被阻塞,繼續(xù)往下走,直到主線程代碼執(zhí)行完畢。
3、主線程代碼執(zhí)行完畢完成后,然后通過Event Loop,也就是事件循環(huán)機制,開始到Event Queue的開頭取出第一個事件,從線程池中分配一個線程去執(zhí)行這個事件,接下來繼續(xù)取出第二個事件,再從線程池中分配一個線程去執(zhí)行,然后第三個,第四個。主線程不斷的檢查事件隊列中是否有未執(zhí)行的事件,直到事件隊列中所有事件都執(zhí)行完了,此后每當(dāng)有新的事件加入到事件隊列中,都會通知主線程按順序取出交EventLoop處理。當(dāng)有事件執(zhí)行完畢后,會通知主線程,主線程執(zhí)行回調(diào),線程歸還給線程池。
總線程不斷重復(fù)第三步
注意:
我們所看到的node.js單線程只是一個js主線程與ui渲染共享一個線程,本質(zhì)上的異步操作還是由線程池完成的,node將所有的阻塞操作都交給了內(nèi)部的線程池去實現(xiàn),本身只負(fù)責(zé)不斷的往返調(diào)度,并沒有進行真正的I/O操作,從而實現(xiàn)異步非阻塞I/O,這便是node單線程和事件驅(qū)動的精髓之處了
總結(jié)
libuv 線程池默認(rèn)打開 4 個,最多打開 128個 線程。(例如:以前 web 服務(wù)器同一時間比如說最多只能接收 100 個請求,多的就無法接收了。nodejs 所謂的高并發(fā)是指可以同時接收 1000、10000 個請求,只不過以排隊的方式在等待。)
主線程執(zhí)行js,是單線程的,js代碼在做大量計算就是cpu密集了。主線程不空閑出來也沒法處理 io 的事,所以就會阻塞了。
回調(diào)只能保證某個請求按照順序執(zhí)行,不能保證多個請求訪問一個資源的先后順序,多個請求訪問一個資源是要加鎖的,用事務(wù)加鎖就行。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
node如何實現(xiàn)cmd彈窗交互之inquirer
這篇文章主要介紹了node如何實現(xiàn)cmd彈窗交互之inquirer問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10node.js基于fs模塊對系統(tǒng)文件及目錄進行讀寫操作的方法詳解
這篇文章主要介紹了node.js基于fs模塊對系統(tǒng)文件及目錄進行讀寫操作的方法,結(jié)合實例形式分析了nodejs使用fs模塊針對文件與目錄的讀寫、創(chuàng)建、刪除等相關(guān)操作技巧,需要的朋友可以參考下2017-11-11Node.js環(huán)境下編寫爬蟲爬取維基百科內(nèi)容的實例分享
WikiPedia平時在國內(nèi)不大好訪問-- 所以用爬蟲一次性把要看的東西都爬下來保存慢慢看還是比較好的XD 這里我們就來看一下Node.js環(huán)境下編寫爬蟲爬取維基百科內(nèi)容的實例分享2016-06-06pnpm workspace管理monorepo項目使用過程詳解
這篇文章主要為大家介紹了pnpm workspace管理monorepo項目使用過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10Node.js 中 cookie-parser 依賴安裝使用詳解
文章介紹了如何在Node.js中使用cookie-parser中間件來解析、設(shè)置、簽名和清除HTTP請求中的Cookie,感興趣的朋友一起看看吧2025-02-02