欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Node中的異步實(shí)現(xiàn)與事件驅(qū)動(dòng)方法是什么

這篇“Node中的異步實(shí)現(xiàn)與事件驅(qū)動(dòng)方法是什么”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Node中的異步實(shí)現(xiàn)與事件驅(qū)動(dòng)方法是什么”文章吧。

創(chuàng)新互聯(lián)是一家專注于網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),嵊泗網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:嵊泗等地區(qū)。嵊泗做網(wǎng)站價(jià)格咨詢:13518219792

Node的特點(diǎn)

計(jì)算機(jī)中的一些任務(wù)一般可以劃分為兩個(gè)類別,一個(gè)類別叫做IO密集型,一個(gè)叫做計(jì)算密集型;對(duì)于計(jì)算密集型的任務(wù),只能不斷榨干CPU的性能,但是對(duì)于IO密集型的任務(wù)來(lái)說(shuō),理想情況下卻并不需要,只需要通知IO設(shè)備進(jìn)行處理,過(guò)一段時(shí)間再來(lái)拿去數(shù)據(jù)就好了。

對(duì)于某些場(chǎng)景有一些互不相關(guān)的任務(wù)需要完成,現(xiàn)行的主流方法有如下兩種:

  • 多線程并行完成:多線程的代價(jià)在于創(chuàng)建線程和執(zhí)行線程上下文切換的開(kāi)銷(xiāo)較大。另外,在復(fù)雜的業(yè)務(wù)中,多線程編程經(jīng)常面臨鎖、狀態(tài)同步等問(wèn)題;

  • 單線程順序執(zhí)行:易于表達(dá),但串行執(zhí)行的缺點(diǎn)在于性能,任意一個(gè)略慢的任務(wù)都會(huì)導(dǎo)致后續(xù)代碼被組設(shè)

node在兩者之前給出了它的方案:利用單線程,遠(yuǎn)離多線程死鎖、狀態(tài)同步等問(wèn)題;利用異步IO,讓單線程遠(yuǎn)離阻塞,以更好地使用CPU

Node是如何實(shí)現(xiàn)異步的

剛才講了node在多任務(wù)處理的方案,但是node內(nèi)部想要實(shí)現(xiàn)卻并不容易,下面介紹操作系統(tǒng)的幾個(gè)概念,方面后續(xù)大家更好理解,后面再講一講異步的實(shí)現(xiàn)以及node的事件循環(huán)機(jī)制:

阻塞IO與非阻塞IO

  • 阻塞IO:應(yīng)用層面發(fā)起IO調(diào)用之后,就一直等待數(shù)據(jù),等操作系統(tǒng)內(nèi)核層面完成所有操作后,調(diào)用才結(jié)束;

操作系統(tǒng)中一切皆文件,輸入輸出設(shè)備同樣被抽象為了文件,內(nèi)核在執(zhí)行IO操作時(shí),通過(guò)文件描述符進(jìn)行管理

  • 非阻塞IO:差別為調(diào)用后立即返回一個(gè)文件描述符,并不等待,這時(shí)候CPU的時(shí)間片就可以用來(lái)處理其他事務(wù),之后可以通過(guò)這個(gè)文件描述符進(jìn)行結(jié)果的獲取;

非阻塞IO存在的一些問(wèn)題:雖然其讓CPU的利用率提高了,但是由于立即返回的是一個(gè)文件描述符,我們并不知道IO操作什么時(shí)候完成,為了確認(rèn)狀態(tài)變更,我們只能作輪詢操作

不同的輪詢方法

  • read :最原始、性能最低的一種,通過(guò)重復(fù)檢查IO狀態(tài)來(lái)完成完整數(shù)據(jù)的獲取

  • select:通過(guò)對(duì)文件描述符上的事件狀態(tài)來(lái)進(jìn)行判斷,相對(duì)來(lái)說(shuō)消耗更少;缺點(diǎn)就是它采用了一個(gè)1024長(zhǎng)度的數(shù)組來(lái)存儲(chǔ)狀態(tài),所以它最多可以同時(shí)檢查1024個(gè)文件描述符

  • poll:由于select的限制,poll改進(jìn)為鏈表的存儲(chǔ)方式,其他的基本都一致;但是當(dāng)文件描述符較多的時(shí)候,它的性能還是非常低下的

  • eopll:該方案是linux下效率最高的IO事件通知機(jī)制,在進(jìn)入輪詢的時(shí)候如果沒(méi)有檢查IO事件,將會(huì)進(jìn)行休眠,直到事件發(fā)生將它喚醒

  • kqueue:與epoll類似,不過(guò)僅在FreeBSD系統(tǒng)下存在

盡管epoll利用了事件來(lái)降低對(duì)CPU的耗用,但休眠期間CPU幾乎是閑置的;我們期待的異步IO應(yīng)該是應(yīng)用程序發(fā)起非阻塞調(diào)用,無(wú)須通過(guò)遍歷或事件喚醒等方式輪詢,可以直接處理下一個(gè)任務(wù),只需IO完成后通過(guò)信號(hào)或者回調(diào)將數(shù)據(jù)傳遞給應(yīng)用程序即可。

linux下還有中AIO方式就是通過(guò)信號(hào)或回調(diào)來(lái)傳遞數(shù)據(jù)的,不過(guò)只有Linux有,并且有限制無(wú)法利用系統(tǒng)緩存

node中對(duì)于異步IO的實(shí)現(xiàn)

先說(shuō)結(jié)論,node對(duì)異步IO的實(shí)現(xiàn)是通過(guò)多線程實(shí)現(xiàn)的。可能會(huì)混淆的地方就是node內(nèi)部雖然是多線程的,但是我們程序員開(kāi)發(fā)的JavaScript代碼卻僅僅是運(yùn)行在單線程上的。

node通過(guò)部分線程進(jìn)行阻塞IO或者非阻塞IO加上輪詢技術(shù)來(lái)完成數(shù)據(jù)獲取,讓一個(gè)線程進(jìn)行計(jì)算處理,通過(guò)線程之間的通信將IO得到的數(shù)據(jù)進(jìn)行傳遞,這就輕松實(shí)現(xiàn)了異步IO的模擬。

除了異步IO,計(jì)算機(jī)中的其他資源也適用,因?yàn)閘inux中一切皆文件,磁盤(pán)、硬件、套接字等幾乎所有計(jì)算機(jī)資源都被抽象為了文件,接下來(lái)介紹對(duì)計(jì)算機(jī)資源的調(diào)用都以IO為例子。

事件循環(huán)

在進(jìn)程啟動(dòng)時(shí),node便會(huì)創(chuàng)建一個(gè)類似與while(true)的循環(huán),每執(zhí)行一次循環(huán)體的過(guò)程我們成為Tick

簡(jiǎn)單解釋一下:就是每次都從IO觀察者里面獲取執(zhí)行完成的事件(是個(gè)請(qǐng)求對(duì)象,簡(jiǎn)單理解就是包含了請(qǐng)求中產(chǎn)生的一些數(shù)據(jù)),然后沒(méi)有回調(diào)函數(shù)的話就繼續(xù)取出下一個(gè)事件(請(qǐng)求對(duì)象),有回調(diào)就執(zhí)行回調(diào)函數(shù)

異步IO細(xì)節(jié)

注:不同平臺(tái)有不同的細(xì)節(jié)實(shí)現(xiàn),這張圖隱藏了相關(guān)平臺(tái)兼容細(xì)節(jié),比如windows下使用IOCP中的PostQueuedCompletionStatus()提交執(zhí)行狀態(tài),通過(guò)GetQueuedCompletionStatus獲取執(zhí)行完成的請(qǐng)求,并且IOCP內(nèi)部實(shí)現(xiàn)了線程池的細(xì)節(jié),而linux等平臺(tái)通過(guò)eopll實(shí)現(xiàn)這個(gè)過(guò)程,并在libuv下自實(shí)現(xiàn)了線程池

setTimtoutsetInterval

除了IO等計(jì)算機(jī)資源需要異步調(diào)用之外,node本身還存在一些與異步IO無(wú)關(guān)的一些其他異步API

  • setTimeout

  • setInterval

  • setImmediate

  • process.nextTick

該小節(jié)先講解前面兩個(gè)api

它們的實(shí)現(xiàn)原理與異步IO比較類似,只是不需要IO線程池的參與

  • setTimtoutsetInterval創(chuàng)建的定時(shí)器會(huì)被插入到定時(shí)器觀察者內(nèi)部的一個(gè)紅黑樹(shù)中

  • 每次tick執(zhí)行的時(shí)候,會(huì)從該紅黑樹(shù)中迭代取出定時(shí)器對(duì)象,檢查是否超過(guò)定時(shí)時(shí)間

  • 如果超過(guò),就將這個(gè)事件(請(qǐng)求對(duì)象)推入到事件隊(duì)列中,在事件循環(huán)中執(zhí)行其中的回調(diào)函數(shù)

紅黑樹(shù):這里簡(jiǎn)單提一下,就是一種特殊化的平衡二叉樹(shù),可以自平衡,查找效率基本上就是該二叉樹(shù)的深度了O(log2n)O(log_2n)O(log2n)

你有考慮過(guò)這個(gè)問(wèn)題嗎,為什么定時(shí)器不需要線程池的參與了呢,如果你理解了之前章節(jié)對(duì)于異步IO實(shí)現(xiàn)原理的話,相信你應(yīng)該能解釋出來(lái),這里簡(jiǎn)單說(shuō)說(shuō)原因來(lái)加深記憶:

node中的IO線程池是用來(lái)調(diào)用IO并等待數(shù)據(jù)返回(看具體實(shí)現(xiàn))的一種方式,它使JavaScript單線程得以異步調(diào)用IO,并且不需要等待IO執(zhí)行完成(因?yàn)槭荌O線程池做了),并且能獲取到最終的數(shù)據(jù)(通過(guò)觀察者模式:IO觀察者從線程池獲取執(zhí)行完成的事件,事件循環(huán)機(jī)制執(zhí)行后續(xù)的回調(diào)函數(shù))

上述這段話可能有點(diǎn)簡(jiǎn)略,如果你還不明白,可以看下之前的那幾種圖~

process.nextTicksetImmediate

這兩個(gè)函數(shù)都是代表立即異步執(zhí)行一個(gè)函數(shù),那為什么不用setTimeout(() => { ... }, 0)來(lái)完成呢?

  • 定時(shí)器精度不夠

  • 定時(shí)器使用紅黑樹(shù)來(lái)創(chuàng)建定時(shí)器對(duì)象和迭代操作,浪費(fèi)性能

  • process.nextTick更加輕量

輕量具體來(lái)說(shuō):我們?cè)诿看握{(diào)用process.nextTick的時(shí)候,只會(huì)將回調(diào)函數(shù)放入隊(duì)列中,在下一輪Tick時(shí)取出執(zhí)行。定時(shí)器中采用紅黑樹(shù)的方式時(shí)O(log2n)O(log_2n)O(log2n),nextTickO(1)O(1)O(1)

process.nextTicksetImmediate又有什么區(qū)別呢?畢竟它們都是將回調(diào)函數(shù)立即異步執(zhí)行

  • process.nextTick的回調(diào)執(zhí)行優(yōu)先級(jí)高于setImmediate

  • process.nextTick的回調(diào)函數(shù)保存在一個(gè)數(shù)組中,每輪事件循環(huán)下全部執(zhí)行,setImmediate的結(jié)果則是保存在鏈表中,每輪循環(huán)按序執(zhí)行第一個(gè)回調(diào)

注意:之所以process.nextTick的回調(diào)執(zhí)行優(yōu)先級(jí)高于setImmediate,因?yàn)槭录h(huán)對(duì)觀察者的檢查是有順序的,process.nextTick屬于idle觀察者,setImmediate屬于check觀察者。iedl觀察者 > IO 觀察者 > check觀察者

高性能服務(wù)器

對(duì)于網(wǎng)絡(luò)套接字的處理,node也應(yīng)用到了異步IO,網(wǎng)絡(luò)套接字上偵聽(tīng)到的請(qǐng)求都會(huì)形成事件交給IO觀察者,事件循環(huán)會(huì)不停地處理這些網(wǎng)絡(luò)IO事件,如果我們?cè)?code>JavaScrpt層面上有傳入對(duì)應(yīng)的回調(diào)函數(shù),這些回調(diào)函數(shù)就會(huì)在事件循環(huán)中執(zhí)行(處理這些網(wǎng)絡(luò)請(qǐng)求)

常見(jiàn)的服務(wù)器模型:

  • 同步式

  • 每進(jìn)程-->每請(qǐng)求

  • 每線程-->每請(qǐng)求

node采用的是事件驅(qū)動(dòng)的方式處理這些請(qǐng)求,無(wú)需對(duì)每個(gè)請(qǐng)求創(chuàng)建額外的對(duì)應(yīng)線程,可以省略掉創(chuàng)建線程和銷(xiāo)毀線程的開(kāi)銷(xiāo),同時(shí)操作系統(tǒng)的調(diào)度任務(wù)因?yàn)榫€程較少(只有node內(nèi)部實(shí)現(xiàn)的一些線程)上下文切換的代價(jià)很低。

經(jīng)典問(wèn)題--雪崩問(wèn)題的解決:

問(wèn)題描述:服務(wù)器在剛啟動(dòng)時(shí),緩存無(wú)數(shù)據(jù),如果訪問(wèn)量巨大,同一條SQL會(huì)被發(fā)送到數(shù)據(jù)庫(kù)中反復(fù)查詢,影響性能。

解決方案:

const proxy = new events.EventEmitter();
let status = "ready"; // 狀態(tài)鎖,避免反復(fù)查詢

const select = function(callback) {
    proxy.once("selected", callback);  // 綁定一個(gè)只執(zhí)行一次名為selected的事件
    if(status === "ready") {
        status = "pending";
        // sql
        db.select("SQL", (res) => {
            proxy.emit("selected", res); // 觸發(fā)事件,返回查詢數(shù)據(jù)
            status = "ready";
        })
    }
}

使用once將所有請(qǐng)求的回調(diào)都?jí)喝肓耸录?duì)列中,利用其只執(zhí)行一次就會(huì)將監(jiān)視器移除的特點(diǎn),保證每一個(gè)回調(diào)函數(shù)只會(huì)被執(zhí)行一次。對(duì)于相同的SQL語(yǔ)句,保證在同一個(gè)查詢開(kāi)始到結(jié)束的過(guò)程中永遠(yuǎn)只有一次。新到來(lái)的相同調(diào)用只需在隊(duì)列中等待數(shù)據(jù)就緒即可,一旦查詢到結(jié)果,得到的結(jié)果就可以被這些調(diào)用共同使用。

以上就是關(guān)于“Node中的異步實(shí)現(xiàn)與事件驅(qū)動(dòng)方法是什么”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)站題目:Node中的異步實(shí)現(xiàn)與事件驅(qū)動(dòng)方法是什么
本文網(wǎng)址:http://www.chinadenli.net/article36/iigcpg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄關(guān)鍵詞優(yōu)化App設(shè)計(jì)微信小程序做網(wǎng)站網(wǎng)站策劃

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷(xiāo)型網(wǎng)站建設(shè)