原文
先說(shuō)1.1總攬:
Reactor模式
Reactor模式中的協(xié)調(diào)機(jī)制Event Loop
Reactor模式中的事件分離器Event Demultiplexer
一些Event Demultiplexer處理不了的復(fù)雜I/O接口比如File I/O、DNS等
復(fù)雜I/O的解決方案
未完待續(xù)
前言nodejs和其他編程平臺(tái)的區(qū)別在于如何去處理I/O接口,我們聽(tīng)一個(gè)人介紹nodejs,總是會(huì)說(shuō)是一個(gè)基于v8引擎,沒(méi)有堵塞,事件驅(qū)動(dòng)的語(yǔ)言,那這些又意味著什么呢?什么叫‘沒(méi)有堵塞’和‘事件驅(qū)動(dòng)’?所有的答案都在nodejs的核心——Event Loop。
在這一系列的帖子中,我們將一起去描述什么是Event Loop,它是如何工作的,它是如何影響我們的應(yīng)用的,如何充分的利用他甚至更多。為什么不用一篇代替一個(gè)系列的帖子呢,因?yàn)檫@樣的話,他就會(huì)變成一個(gè)很長(zhǎng)很長(zhǎng)的帖子,我會(huì)肯定會(huì)錯(cuò)過(guò)很多東西,因此我才把它寫(xiě)成一個(gè)系列,在第一篇帖子中,我將講述nodejs如何工作,如何通過(guò)I/O,他如何與其他平臺(tái)一起工作等。
nodejs工作在一個(gè)事件驅(qū)動(dòng)的模型中,這個(gè)模型涉及一個(gè)事件分離器和事件循環(huán),所有的I/O請(qǐng)求最終將會(huì)生成一個(gè)事件完成、事件失敗或者喚醒其他事件的結(jié)果。這些事件將會(huì)根據(jù)以下規(guī)則做處理:
1.事件分離器收到I/O請(qǐng)求,之后將這些請(qǐng)求委托給相應(yīng)的硬件
2.曾經(jīng)被處理過(guò)的請(qǐng)求(比如來(lái)自可讀取文件的數(shù)據(jù),來(lái)自可讀取接口的數(shù)據(jù)),事件分離器會(huì)為要進(jìn)行的特殊操作添加注冊(cè)回調(diào)程序。
3.如果事件可以在事件循環(huán)中被處理,那么將有序的被執(zhí)行,直到循環(huán)為空
4.如果沒(méi)有事件在事件循環(huán)中,或者事件分離器沒(méi)有添加任何請(qǐng)求,這個(gè) 程序?qū)⒈煌瓿?,否則,程序?qū)牡谝徊皆陂_(kāi)始,進(jìn)行循環(huán)操作。
這整個(gè)工程的協(xié)調(diào)機(jī)制我們叫做Event Loop
Event Loop其實(shí)是一個(gè)單線程的半無(wú)限循環(huán),為什么會(huì)說(shuō)是半無(wú)限呢?因?yàn)樵跊](méi)有工作需要完成的時(shí)候程序會(huì)退出。從開(kāi)發(fā)者的角度來(lái)說(shuō),這些是程序退出的點(diǎn)。
注意:不要把Event Loop和Event Emitter弄混淆,Event Emitter和這個(gè)機(jī)制完全是不同的概念,在最后一篇帖子,我會(huì)解釋Event Emitter是如何通過(guò)Event Loop影響事件的處理。
上面的圖是對(duì)NodeJs如何工作以及展示一種被叫做Reactor Pattern的主要組件的設(shè)計(jì)模式的高級(jí)概覽。
但是真正的復(fù)雜度遠(yuǎn)超于它,那它有多復(fù)雜呢?
Event demultiplexer不是一個(gè)在所有os平臺(tái)中解析所有I/O類型的單一組件。
Event queue在這里展示出來(lái)的不是一個(gè)單一的隊(duì)列,在其中所有類型的事件會(huì)在隊(duì)列中排隊(duì)或者從隊(duì)列中移除,并且I/O不是唯一一個(gè)要排隊(duì)的事件類型
讓我們繼續(xù)深挖
Event DemultiplexerEvent Demultiplexer并不是一個(gè)現(xiàn)實(shí)存在的組件,而是在reactor pattern中的一個(gè)抽象概念。
在現(xiàn)實(shí)中,Event Demultiplexer 在不同的系統(tǒng)中以不同的名字被實(shí)現(xiàn),比如在linux中叫做epoll, 在MacOS中叫做kqueue,在Solaris中叫event post,在window系統(tǒng)下叫做IOCP等。
nodeJS可以使用Event Demultiplexer提供的底層非阻塞、異步硬件I/O功能。
Complexities in File I/O但是令人苦惱的是,不是所有類型的I/O都可以使用Event Demultiplexer被執(zhí)行,甚至是在相同的操作系統(tǒng)中,支持不同類型的I/O也是很復(fù)雜的。
通常來(lái)說(shuō),epoll, kqueue, event ports和IOCP可以使用非阻塞的方式執(zhí)行網(wǎng)絡(luò)I/O。
但是文件I/O就復(fù)雜多了,某些系統(tǒng),比如Linux不支持完全異步的方式去訪問(wèn)文件系統(tǒng),在MacOS系統(tǒng)中文件系統(tǒng)對(duì)事件的發(fā)送和接收會(huì)有限制(你可以在這里了解更多)。
為了提供完全異步而去解決所有文件系統(tǒng)的復(fù)雜性是非常復(fù)雜的,幾乎是不可能的。
Complexities in DNS和文件I/O一樣,由node API提供某些DNS的功能也存在一定的復(fù)雜性。
比如dns.lookup等Node DNS功能訪問(wèn)系統(tǒng)的一些配置文件,例如nsswitch.conf、resolv.conf和/etc/hosts。
上面描述的文件系統(tǒng)復(fù)雜性也適用于dns.resolve函數(shù)。
The solution?因此,引入了一個(gè)線程池來(lái)支持I/O功能,這些功能不能由硬件異步I/O實(shí)用程序(如epoll / kqueue / event ports或IOCP)直接解決。
現(xiàn)在我們知道不是所有的I/O功能都可以在線程池中運(yùn)行。nodeJS已經(jīng)盡最大努力來(lái)使用非阻塞和硬件的異步I/O方式來(lái)完成大部分I/O功能,但是對(duì)于一些復(fù)雜的、阻塞的I/O還是通過(guò)引入一個(gè)線程池的方式來(lái)解決
未完待續(xù)該篇先翻譯到這,有些地方翻譯的不好請(qǐng)指出,過(guò)幾天我會(huì)繼續(xù)出第二篇。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/92567.html
摘要:引言作為服務(wù)器的優(yōu)勢(shì)就在于適合處理高并發(fā)的請(qǐng)求,對(duì)于網(wǎng)站后臺(tái)這種密集型的后臺(tái)尤其有優(yōu)勢(shì),其核心就在于是一個(gè)異步非阻塞模型。關(guān)于異步,同步,阻塞,非阻塞這些概念,本文不做討論。另外兩個(gè)的調(diào)用時(shí)間需要判斷是否都在主線程中被執(zhí)行。 引言 node作為服務(wù)器的優(yōu)勢(shì)就在于適合處理高并發(fā)的請(qǐng)求,對(duì)于web網(wǎng)站后臺(tái)這種I/O密集型的后臺(tái)尤其有優(yōu)勢(shì),其核心就在于node是一個(gè)異步非阻塞模型。關(guān)于異步,...
摘要:前端日?qǐng)?bào)精選大前端公共知識(shí)梳理這些知識(shí)你都掌握了嗎以及在項(xiàng)目中的實(shí)踐深入貫徹閉包思想,全面理解閉包形成過(guò)程重溫核心概念和基本用法前端學(xué)習(xí)筆記自定義元素教程阮一峰的網(wǎng)絡(luò)日志中文譯回調(diào)是什么鬼掘金譯年,一個(gè)開(kāi)發(fā)者的好習(xí)慣知乎專 2017-06-23 前端日?qǐng)?bào) 精選 大前端公共知識(shí)梳理:這些知識(shí)你都掌握了嗎?Immutable.js 以及在 react+redux 項(xiàng)目中的實(shí)踐深入貫徹閉包思...
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...
摘要:事件處理器,則是當(dāng)指定事件觸發(fā)時(shí),執(zhí)行的一段代碼。事件循環(huán)以一個(gè)無(wú)限循環(huán)的形式啟動(dòng),存在于二進(jìn)制文件里函數(shù)的最后,當(dāng)沒(méi)有更多可被執(zhí)行的事件處理器時(shí),它就退出。 前言 如果你了解過(guò)Node.js,那么你一定聽(tīng)說(shuō)過(guò)事件循環(huán)。你一定想知道它為什么那么特殊,并且為什么你需要關(guān)注它?此時(shí)此刻的你,可能已經(jīng)寫(xiě)過(guò)許多基于Express.js的后端代碼,但沒(méi)有接觸到任何的循環(huán)。 在下文中,我們會(huì)先在一...
摘要:?jiǎn)尉€程的好處簡(jiǎn)單,處理時(shí)不會(huì)出現(xiàn)并發(fā)競(jìng)爭(zhēng)問(wèn)題異步的必要性讓用戶體驗(yàn)更流暢如何實(shí)現(xiàn)異步見(jiàn)參考,,調(diào)用棧函數(shù)執(zhí)行上下文。單線程只能有一個(gè)并且每次只能執(zhí)行一個(gè)任務(wù)。 參考: JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop 深入理解JavaScript的執(zhí)行過(guò)程--單線程的JS 細(xì)說(shuō)JavaScript單線程的一些事 The JavaScript Event Loop: Exp...
閱讀 1462·2021-11-25 09:43
閱讀 2326·2021-09-27 13:36
閱讀 1170·2021-09-04 16:40
閱讀 2043·2019-08-30 11:12
閱讀 3370·2019-08-29 14:14
閱讀 634·2019-08-28 17:56
閱讀 1412·2019-08-26 13:50
閱讀 1319·2019-08-26 13:29