站長(zhǎng)資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        nodejs是單進(jìn)程的嗎

        nodejs是單進(jìn)程。Node遵循的是單線程單進(jìn)程的模式,但其基于事件驅(qū)動(dòng)、異步非阻塞模式,可以應(yīng)用于高并發(fā)場(chǎng)景,避免了線程創(chuàng)建、線程之間上下文切換所產(chǎn)生的資源開銷。

        nodejs是單進(jìn)程的嗎

        本教程操作環(huán)境:windows7系統(tǒng)、nodejs 12.19.0版、Dell G3電腦。

        進(jìn)程

        進(jìn)程 Process 是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ),進(jìn)程是線程的容器 (來自百科) 。進(jìn)程是資源分配的最小單位。我們啟動(dòng)一個(gè)服務(wù)、運(yùn)行一個(gè)實(shí)例,就是開一個(gè)服務(wù)進(jìn)程,例如 Java 里的 JVM 本身就是一個(gè)進(jìn)程,Node.js 里通過 node app.js 開啟一個(gè)服務(wù)進(jìn)程,多進(jìn)程就是進(jìn)程的復(fù)制 (fork) ,fork 出來的每個(gè)進(jìn)程都擁有自己的獨(dú)立空間地址、數(shù)據(jù)棧,一個(gè)進(jìn)程無法訪問另外一個(gè)進(jìn)程里定義的變量、數(shù)據(jù)結(jié)構(gòu),只有建立了 IPC 通信,進(jìn)程之間才可數(shù)據(jù)共享。

        線程

        線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,首先我們要清楚線程是隸屬于進(jìn)程的,被包含于進(jìn)程之中。 一個(gè)線程只能隸屬于一個(gè)進(jìn)程,但是一個(gè)進(jìn)程是可以擁有多個(gè)線程的。 單線程 單線程就是一個(gè)進(jìn)程只開一個(gè)線程 Javascript 就是屬于單線程,程序順序執(zhí)行(這里暫且不提JS異步),可以想象一下隊(duì)列,前面一個(gè)執(zhí)行完之后,后面才可以執(zhí)行,當(dāng)你在使用單線程語言編碼時(shí)切勿有過多耗時(shí)的同步操作,否則線程會(huì)造成阻塞,導(dǎo)致后續(xù)響應(yīng)無法處理。你如果采用 Javascript 進(jìn)行編碼時(shí)候,請(qǐng)盡可能的利用 Javascript 異步操作的特性。

        nodejs單進(jìn)程單線程事件驅(qū)動(dòng)

        Node遵循的是單線程單進(jìn)程的模式,node的單線程是指js的引擎只有一個(gè)實(shí)例,且在nodejs的主線程中執(zhí)行,同時(shí)node以事件驅(qū)動(dòng)的方式處理IO等異步操作。node的單線程模式,只維持一個(gè)主線程,大大減少了線程間切換的開銷,但是會(huì)有多個(gè)worker線程,用于執(zhí)行異步操作。

        但是node的單線程使得在主線程不能進(jìn)行CPU密集型操作,否則會(huì)阻塞主線程。對(duì)于CPU密集型操作,在node中通過 child_process 可以創(chuàng)建獨(dú)立的子進(jìn)程,父子進(jìn)程通過IPC通信,子進(jìn)程可以是外部應(yīng)用也可以是node子程序,子進(jìn)程執(zhí)行后可以將結(jié)果返回給父進(jìn)程。

        Node.js的運(yùn)行機(jī)制

        • V8引擎解析JavaScript腳本。
        • 解析后的代碼,調(diào)用Node API。
        • libuv庫負(fù)責(zé)Node API的執(zhí)行。它將不同的任務(wù)分配給不同的worker線程,形成一個(gè)Event Loop(事件循環(huán)),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給V8引擎。
        • V8引擎再將結(jié)果返回給用戶。
          nodejs是單進(jìn)程的嗎

        這個(gè)圖是整個(gè) Node.js 的運(yùn)行原理,從左到右,從上到下,Node.js 被分為了四層,分別是 應(yīng)用層、V8引擎層、Node API層 和 LIBUV層。

        • 應(yīng)用層: 即 JavaScript 交互層,常見的就是 Node.js 的模塊,比如 http,fs
        • V8引擎層: 即利用 V8 引擎來解析JavaScript 語法,進(jìn)而和下層 API 交互
        • NodeAPI層: 為上層模塊提供系統(tǒng)調(diào)用,一般是由 C 語言來實(shí)現(xiàn),和操作系統(tǒng)進(jìn)行交互 。
        • LIBUV層: 是跨平臺(tái)的底層封裝,實(shí)現(xiàn)了 事件循環(huán)、文件操作等,是 Node.js 實(shí)現(xiàn)異步的核心

        Node.js 事件循環(huán)

        Node.js 通常情況下是單進(jìn)程的。

        • 主線程運(yùn)行 V8 和 Javascript
        • 多個(gè)子線程通過 事件循環(huán) 被調(diào)度

        事件循環(huán):

        事件循環(huán)是一種編程構(gòu)造,用于等待和分派程序中的事件或消息, 主線程從"任務(wù)隊(duì)列"中讀取事件,這個(gè)過程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))

        事件隊(duì)列:

        當(dāng)用戶的網(wǎng)絡(luò)請(qǐng)求或者其它的異步操作到來時(shí),node都會(huì)把它放到Event Queue之中,此時(shí)并不會(huì)立即執(zhí)行它,代碼也不會(huì)被阻塞,繼續(xù)往下走,直到主線程代碼執(zhí)行完畢。

        任務(wù)隊(duì)列:

        任務(wù)隊(duì)列"是一個(gè)事件的隊(duì)列(也可以理解成消息的隊(duì)列),IO設(shè)備完成一項(xiàng)任務(wù),就在"任務(wù)隊(duì)列"中添加一個(gè)事件,表示相關(guān)的異步任務(wù)可以進(jìn)入"執(zhí)行棧"了。主線程讀取"任務(wù)隊(duì)列",就是讀取里面有哪些事件。

        事件驅(qū)動(dòng):

        實(shí)質(zhì)是通過主循環(huán)加事件觸發(fā)方式運(yùn)行程序
        node
        Node.js 不是一門語言也不是框架,它只是基于 Google V8 引擎的 JavaScript 運(yùn)行時(shí)環(huán)境,是對(duì) js 功能的拓展。提供了網(wǎng)絡(luò)、文件、dns 解析、進(jìn)程線程等功能。

        libuv
        libuv是專門為Node.js開發(fā)的一個(gè)封裝庫,提供跨平臺(tái)的異步I/O能力。

        注意:

        • 一個(gè)事件循環(huán)有一個(gè)或多個(gè)任務(wù)隊(duì)列。一個(gè)任務(wù)隊(duì)列是一組的任務(wù)

        • Libuv 主要是,利用系統(tǒng)提供的事件驅(qū)動(dòng)模塊解決網(wǎng)絡(luò)異步 IO,利用線程池解決文件IO。另外還實(shí)現(xiàn)了定時(shí)器,對(duì)進(jìn)程、線程等使用進(jìn)行了封裝。

        其實(shí)這里的事件循環(huán)和js在瀏覽器的事件循環(huán)是一樣的,主線程允許同步代碼,異步代碼放到對(duì)應(yīng)的工作線程中執(zhí)行,回調(diào)執(zhí)行結(jié)果后放進(jìn)事件隊(duì)列,待主線程執(zhí)行事件隊(duì)列的任務(wù)。

        事件驅(qū)動(dòng)+事件循環(huán)實(shí)現(xiàn)高并發(fā)

        具體執(zhí)行順序:

        1、每個(gè)Node.js進(jìn)程只有一個(gè)主線程在執(zhí)行程序代碼,形成一個(gè)執(zhí)行棧(execution context stack)

        2、主線程之外,還維護(hù)了一個(gè)"事件隊(duì)列"(Event queue)。當(dāng)用戶的網(wǎng)絡(luò)請(qǐng)求或者其它的異步操作到來時(shí),node都會(huì)把它放到Event Queue之中,此時(shí)并不會(huì)立即執(zhí)行它,代碼也不會(huì)被阻塞,繼續(xù)往下走,直到主線程代碼執(zhí)行完畢。

        3、主線程代碼執(zhí)行完畢完成后,然后通過Event Loop,也就是事件循環(huán)機(jī)制,開始到Event Queue的開頭取出第一個(gè)事件,從線程池中分配一個(gè)線程去執(zhí)行這個(gè)事件,接下來繼續(xù)取出第二個(gè)事件,再?gòu)木€程池中分配一個(gè)線程去執(zhí)行,然后第三個(gè),第四個(gè)。主線程不斷的檢查事件隊(duì)列中是否有未執(zhí)行的事件,直到事件隊(duì)列中所有事件都執(zhí)行完了,此后每當(dāng)有新的事件加入到事件隊(duì)列中,都會(huì)通知主線程按順序取出交EventLoop處理。當(dāng)有事件執(zhí)行完畢后,會(huì)通知主線程,主線程執(zhí)行回調(diào),線程歸還給線程池。

        注意

        我們所看到的node.js單線程只是一個(gè)js主線程與ui渲染共享一個(gè)線程,本質(zhì)上的異步操作還是由線程池完成的,node將所有的阻塞操作都交給了內(nèi)部的線程池去實(shí)現(xiàn),本身只負(fù)責(zé)不斷的往返調(diào)度,并沒有進(jìn)行真正的I/O操作,從而實(shí)現(xiàn)異步非阻塞I/O,這便是node單線程和事件驅(qū)動(dòng)的精髓之處了。

        總結(jié):

        1、libuv 線程池默認(rèn)打開 4 個(gè),最多打開 128個(gè) 線程。(例如:以前 web 服務(wù)器同一時(shí)間比如說最多只能接收 100 個(gè)請(qǐng)求,多的就無法接收了,服務(wù)器就掛掉了。nodejs 所謂的高并發(fā)是指可以同時(shí)接收 1000、10000 個(gè)請(qǐng)求,只不過以排隊(duì)的方式在等待。

        2、主線程執(zhí)行js,是單線程的,js代碼在做大量計(jì)算就是cpu密集了。主線程不空閑出來也沒法處理 io 的事,所以就會(huì)阻塞了。

        3、回調(diào)只能保證某個(gè)請(qǐng)求按照順序執(zhí)行,不能保證多個(gè)請(qǐng)求訪問一個(gè)資源的先后順序,多個(gè)請(qǐng)求訪問一個(gè)資源是要加鎖的,用事務(wù)加鎖就行。

        【推薦學(xué)習(xí):《nodejs 教程》】

        贊(0)
        分享到: 更多 (0)
        網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
        主站蜘蛛池模板: 国产精品亚洲高清一区二区 | 亚洲高清专区日韩精品| 精品国产一区二区三区久久久狼 | 日本精品少妇一区二区三区| laowang在线精品视频| 无码国内精品人妻少妇蜜桃视频| 精品久久久久久久中文字幕| 久久青草国产精品一区| 精品国产第一国产综合精品| 亚洲精品无码久久久久sm| 精品久久久无码中文字幕天天| 88久久精品无码一区二区毛片| 国产成人精品2021| 欧美精品一区二区蜜臀亚洲 | 亚洲综合国产精品| 国产成人精品视频一区二区不卡| 最新精品露脸国产在线| 精品国产三级a乌鸦在线观看| 337P亚洲精品色噜噜| 国产精品视频一区国模私拍 | 久久国产乱子伦精品免费强| 国产精品va无码一区二区| 日本伊人精品一区二区三区| 一本久久精品一区二区| 亚洲国产精品成人久久蜜臀| 日韩精品一二三区| 麻豆精品三级全部视频 | 亚洲精品无码av人在线观看 | 久久精品不卡| 国语自产精品视频| 精品国产一区二区三区AV性色| 国产精品女人呻吟在线观看| 国产av无码专区亚洲国产精品| 2020最新久久久视精品爱| 91精品国产高清久久久久久91| 四虎永久在线精品国产免费| 精品一区二区三区在线视频| 午夜精品视频在线| 99久久伊人精品综合观看| 国产精品成人99久久久久91gav| 国产VA免费精品高清在线|