欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Node.js異步I/O學(xué)習(xí)筆記

 更新時(shí)間:2014年11月04日 11:20:51   投稿:junjie  
這篇文章主要介紹了Node.js異步I/O學(xué)習(xí)筆記,本文詳細(xì)講解了異步I/O的基本概念、Node的異步I/O、非I/O的異步API、事件驅(qū)動(dòng)與高性能服務(wù)器等內(nèi)容,需要的朋友可以參考下

“異步”這個(gè)名詞的大規(guī)模流行是在Web 2.0浪潮中,它伴隨著Javascript和AJAX席卷了Web。但在絕大多數(shù)高級(jí)編程語(yǔ)言中,異步并不多見(jiàn)。PHP最能體現(xiàn)這個(gè)特點(diǎn):它不僅屏蔽了異步,甚至連多線(xiàn)程也不提供,PHP都是以同步阻塞的方式來(lái)執(zhí)行。這樣的優(yōu)點(diǎn)利于程序猿順序編寫(xiě)業(yè)務(wù)邏輯,但在復(fù)雜的網(wǎng)絡(luò)應(yīng)用中,阻塞導(dǎo)致它無(wú)法更好地并發(fā)。

在服務(wù)器端,I/O非常昂貴,分布式I/O更加昂貴,只有后端能快速響應(yīng)資源,前端的體驗(yàn)才能變得更好。Node.js是首個(gè)將異步作為主要編程方式和設(shè)計(jì)理念的平臺(tái),伴隨著異步I/O的還有事件驅(qū)動(dòng)和單線(xiàn)程,它們構(gòu)成Node的基調(diào)。本文將介紹Node是如何實(shí)現(xiàn)異步I/O的。

1. 基本概念

“異步”與“非阻塞”聽(tīng)起來(lái)似乎是一回事,從實(shí)際效果而言,這兩者都達(dá)到了并行的目的。但是從計(jì)算機(jī)內(nèi)核I/O而言,只有兩種方式:阻塞與非阻塞。因此異步/同步和阻塞/非阻塞實(shí)際上是兩回事。

1.1 阻塞I/O與非阻塞I/O

阻塞I/O的一個(gè)特點(diǎn)是調(diào)用之后一定要等到系統(tǒng)內(nèi)核層面完成所有操作后,調(diào)用才結(jié)束。以讀取磁盤(pán)上的一個(gè)文件為例,系統(tǒng)內(nèi)核在完成磁盤(pán)尋道、讀取數(shù)據(jù)、復(fù)制數(shù)據(jù)到內(nèi)存中后,這個(gè)調(diào)用才結(jié)束。

阻塞I/O造成CPU等待I/O,浪費(fèi)等待時(shí)間,CPU的處理能力不能得到充分利用。非阻塞I/O的特點(diǎn)就是調(diào)用之后會(huì)立即返回,返回后CPU的時(shí)間片可以用來(lái)處理其他事務(wù)。由于完整的I/O并沒(méi)有完成,立即返回的并不是業(yè)務(wù)層期待的數(shù)據(jù),而僅僅是當(dāng)前調(diào)用的狀態(tài)。為了獲取完整的數(shù)據(jù),應(yīng)用程序需要重復(fù)調(diào)用I/O操作來(lái)確認(rèn)是否完成(即輪詢(xún))。輪詢(xún)技術(shù)要以下幾種:

1.read:通過(guò)重復(fù)調(diào)用來(lái)檢查I/O狀態(tài),是最原始性能最低的一種方式
2.select:對(duì)read的改進(jìn),通過(guò)對(duì)文件描述符上的事件狀態(tài)來(lái)進(jìn)行判斷。缺點(diǎn)是文件描述符最大的數(shù)量有限制
3.poll:對(duì)select的改進(jìn),采用鏈表的方式避免最大數(shù)量限制,但描述符較多時(shí),性能還是十分低下
4.epoll:進(jìn)入輪詢(xún)時(shí)若沒(méi)有檢查到I/O事件,將會(huì)進(jìn)行休眠,直到事件發(fā)生將其喚醒。這是當(dāng)前Linux下效率最高的I/O事件通知機(jī)制

輪詢(xún)滿(mǎn)足了非阻塞I/O確保獲取完整數(shù)據(jù)的需求,但對(duì)于應(yīng)用程序而言,它仍然只能算作一種同步,因?yàn)橐廊恍枰却齀/O完全返回。等待期間,CPU要么用于遍歷文件描述符的狀態(tài),要么用于休眠等待事件發(fā)生。

1.2 理想與現(xiàn)實(shí)中的異步I/O

完美的異步I/O應(yīng)該是應(yīng)用程序發(fā)起非阻塞調(diào)用,無(wú)需通過(guò)輪詢(xún)就可以直接處理下一個(gè)任務(wù),只需在I/O完成后通過(guò)信號(hào)或回調(diào)將數(shù)據(jù)傳遞給應(yīng)用程序即可。

現(xiàn)實(shí)中的異步I/O在不同操作系統(tǒng)下有不同的實(shí)現(xiàn),如*nix平臺(tái)采用自定義的線(xiàn)程池,Windows平臺(tái)采用IOCP模型。Node提供了libuv作為抽象封裝層來(lái)封裝平臺(tái)兼容性判斷,并保證上層Node與下層各平臺(tái)異步I/O的實(shí)現(xiàn)各自獨(dú)立。另外需要強(qiáng)調(diào)的是我們經(jīng)常提到Node是單線(xiàn)程的,這僅僅是指Javascript的執(zhí)行在單線(xiàn)程中,實(shí)際在Node內(nèi)部完成I/O任務(wù)的都另有線(xiàn)程池。

2. Node的異步I/O

2.1 事件循環(huán)

Node的執(zhí)行模型實(shí)際上是事件循環(huán)。在進(jìn)程啟動(dòng)時(shí),Node會(huì)創(chuàng)建一個(gè)無(wú)限循環(huán),每一次執(zhí)行循環(huán)體的過(guò)程成為一次Tick。每個(gè)Tick過(guò)程就是查看是否有事件等待處理,如果有則取出事件及其相關(guān)的回調(diào)函數(shù),若存在關(guān)聯(lián)的回調(diào)函數(shù)則執(zhí)行它們,然后進(jìn)入下一個(gè)循環(huán)。如果不再有事件處理,就退出進(jìn)程。

2.2 觀(guān)察者

每個(gè)事件循環(huán)中有若干個(gè)觀(guān)察者,通過(guò)向這些觀(guān)察者詢(xún)問(wèn)來(lái)判斷是否有事件要處理。事件循環(huán)是一個(gè)典型的生產(chǎn)者/消費(fèi)者模型。在Node中,事件主要來(lái)源于網(wǎng)絡(luò)請(qǐng)求、文件I/O等,這些事件都有對(duì)應(yīng)的網(wǎng)絡(luò)I/O觀(guān)察者、文件I/O觀(guān)察者等,事件循環(huán)則從觀(guān)察者那里取出事件并處理。

2.3 請(qǐng)求對(duì)象

從Javascript發(fā)起調(diào)用到內(nèi)核執(zhí)行完I/O操作的過(guò)渡過(guò)程中,存在一種中間產(chǎn)物,叫做請(qǐng)求對(duì)象。以最簡(jiǎn)單的Windows下fs.open()方法(根據(jù)指定路徑和參數(shù)去打開(kāi)一個(gè)文件并得到一個(gè)文件描述符)為例,從JS調(diào)用到內(nèi)建模塊通過(guò)libuv進(jìn)行系統(tǒng)調(diào)用,實(shí)際上是調(diào)用了uv_fs_open()方法。在調(diào)用過(guò)程中,創(chuàng)建了一個(gè)FSReqWrap請(qǐng)求對(duì)象,從JS層傳入的參數(shù)和方法都封裝在這個(gè)請(qǐng)求對(duì)象中,其中我們最為關(guān)注的回調(diào)函數(shù)被設(shè)置在這個(gè)對(duì)象的oncompete_sym屬性上。對(duì)象包裝完畢后,將FSReqWrap對(duì)象推入線(xiàn)程池中等待執(zhí)行。

至此,JS調(diào)用立即返回,JS線(xiàn)程可以繼續(xù)執(zhí)行后續(xù)操作。當(dāng)前的I/O操作在線(xiàn)程池中等待執(zhí)行,這就完成了異步調(diào)用的第一階段。

2.4 執(zhí)行回調(diào)

回調(diào)通知是異步I/O的第二階段。線(xiàn)程池中的I/O操作調(diào)用完畢后,會(huì)將獲取的結(jié)果儲(chǔ)存起來(lái),然后通知IOCP當(dāng)前對(duì)象操作已完成,并將線(xiàn)程歸還線(xiàn)程池。在每次Tick的執(zhí)行中,事件循環(huán)的I/O觀(guān)察者會(huì)調(diào)用相關(guān)的方法檢查線(xiàn)程池中是否有執(zhí)行完的請(qǐng)求,如果存在,會(huì)將請(qǐng)求對(duì)象加入到I/O觀(guān)察者的隊(duì)列中,然后將其當(dāng)做事件處理。

3. 非I/O的異步API

Node中還存在一些與I/O無(wú)關(guān)的異步API,例如定時(shí)器setTimeout()、setInterval(),立即異步執(zhí)行任務(wù)的process.nextTick()和setImmdiate()等,這里略微介紹一下。

3.1 定時(shí)器API

setTimeout()和setInterval()瀏覽器端的API是一致的,它們的實(shí)現(xiàn)原理與異步I/O類(lèi)似,只是不需要I/O線(xiàn)程池的參與。調(diào)用定時(shí)器API創(chuàng)建的定時(shí)器會(huì)被插入到定時(shí)器觀(guān)察者內(nèi)部的一棵紅黑樹(shù)中,每次事件循環(huán)的Tick都會(huì)從紅黑樹(shù)中迭代取出定時(shí)器對(duì)象,檢查是否超過(guò)定時(shí)時(shí)間,若超過(guò)就形成一個(gè)事件,回調(diào)函數(shù)立即被執(zhí)行。定時(shí)器的主要問(wèn)題在于它的定時(shí)時(shí)間并非特別精確(毫秒級(jí),在容忍范圍內(nèi))。

3.2 立即異步執(zhí)行任務(wù)API

在Node出現(xiàn)之前,很多人也許為了立即異步執(zhí)行一個(gè)任務(wù),會(huì)這樣調(diào)用:

復(fù)制代碼 代碼如下:

setTimeout(function() {
    // TODO
}, 0);

由于事件循環(huán)的特點(diǎn),定時(shí)器的精確度不夠,而且采用定時(shí)器需要使用紅黑樹(shù),各種操作時(shí)間復(fù)雜度為O(log(n))。而process.nextTick()方法只會(huì)將回調(diào)函數(shù)放入隊(duì)列中,在下一輪Tick時(shí)取出執(zhí)行,復(fù)雜度為O(1)更為高效。

此外還有一個(gè)setImmediate()方法和上述方法類(lèi)似,都是將回調(diào)函數(shù)延遲執(zhí)行。不過(guò)前者的優(yōu)先級(jí)要比后者高,這是因?yàn)槭录h(huán)對(duì)觀(guān)察者的檢查是有先后順序的。另外,前者的回調(diào)函數(shù)保存在一個(gè)數(shù)組中,每輪Tick會(huì)將數(shù)組中的所有回調(diào)函數(shù)全部執(zhí)行完;后者結(jié)果保存在鏈表中,每輪Tick只會(huì)執(zhí)行一個(gè)回調(diào)函數(shù)。

4. 事件驅(qū)動(dòng)與高性能服務(wù)器

前面以fs.open()為例闡述了Node如何實(shí)現(xiàn)異步I/O。事實(shí)上對(duì)網(wǎng)絡(luò)套接字的處理,Node也應(yīng)用了異步I/O,這也是Node構(gòu)建Web服務(wù)器的基礎(chǔ)。經(jīng)典的服務(wù)器模型有:

1.同步式:一次只能處理一個(gè)請(qǐng)求,其余請(qǐng)求都處于等待狀態(tài)
2.每進(jìn)程/每請(qǐng)求:為每個(gè)請(qǐng)求啟動(dòng)一個(gè)進(jìn)程,但系統(tǒng)資源有限,不具備擴(kuò)展性
3.每線(xiàn)程/每請(qǐng)求:為每個(gè)請(qǐng)求啟動(dòng)一個(gè)線(xiàn)程。線(xiàn)程比進(jìn)程要輕量,但每個(gè)線(xiàn)程都占用一定內(nèi)存,當(dāng)大并發(fā)請(qǐng)求到來(lái)時(shí),內(nèi)存很快就會(huì)用光

著名的Apache采用的就是每線(xiàn)程/每請(qǐng)求的形式,這也是它難以應(yīng)對(duì)高并發(fā)的原因。Node通過(guò)事件驅(qū)動(dòng)方式處理請(qǐng)求,可以省掉創(chuàng)建和銷(xiāo)毀線(xiàn)程的開(kāi)銷(xiāo),同時(shí)操作系統(tǒng)在調(diào)度任務(wù)時(shí)因?yàn)榫€(xiàn)程較少,上下文切換的代價(jià)也很低。即使在大量連接的情況下,Node也能有條不紊地處理請(qǐng)求。

知名服務(wù)器Nginx也摒棄了多線(xiàn)程的方式,采用和Node一樣的事件驅(qū)動(dòng)方式。如今Nginx大有取代Apache之勢(shì)。Nginx采用純C編寫(xiě),性能較高,但是它僅適合做Web服務(wù)器,用于反向代理或負(fù)載均衡等。Node可以構(gòu)建與Nginx相同的功能,也可以處理各種具體業(yè)務(wù),自身性能也不錯(cuò)。在實(shí)際項(xiàng)目中,我們可以結(jié)合它們各自有點(diǎn),以達(dá)到應(yīng)用的最佳性能。

相關(guān)文章

  • node.js中的console.warn方法使用說(shuō)明

    node.js中的console.warn方法使用說(shuō)明

    這篇文章主要介紹了node.js中的console.warn方法使用說(shuō)明,本文介紹了console.warn的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • Nodejs Buffer的使用及Stream流和事件機(jī)制詳解

    Nodejs Buffer的使用及Stream流和事件機(jī)制詳解

    這篇文章主要為大家介紹了Nodejs Buffer的使用及Stream流和事件機(jī)制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 利用nodejs監(jiān)控文件變化并使用sftp上傳到服務(wù)器

    利用nodejs監(jiān)控文件變化并使用sftp上傳到服務(wù)器

    這篇文章主要介紹了利用nodejs監(jiān)控文件變化并使用sftp上傳到服務(wù)器的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • 詳解nodejs 文本操作模塊-fs模塊(二)

    詳解nodejs 文本操作模塊-fs模塊(二)

    這篇文章主要介紹了詳解nodejs 文本操作模塊-fs模塊(二),主要包括文件的讀寫(xiě)操作,有興趣的可以了解一下。
    2016-12-12
  • 用nodejs的實(shí)現(xiàn)原理和搭建服務(wù)器(動(dòng)態(tài))

    用nodejs的實(shí)現(xiàn)原理和搭建服務(wù)器(動(dòng)態(tài))

    下面小編就為大家?guī)?lái)一篇用nodejs的實(shí)現(xiàn)原理和搭建服務(wù)器(動(dòng)態(tài))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • NodeJS學(xué)習(xí)筆記之MongoDB模塊

    NodeJS學(xué)習(xí)筆記之MongoDB模塊

    nodejs是個(gè)強(qiáng)大的平臺(tái),有基本功能,而且可以?huà)旌芏嗄K。我們現(xiàn)在需要和mongodb連接的驅(qū)動(dòng),就類(lèi)似比如mysql的java驅(qū)動(dòng)一樣。nodejs有好幾個(gè)mongodb的第三方驅(qū)動(dòng)。和jdbc不一樣,沒(méi)有標(biāo)準(zhǔn)。所以需要到驅(qū)動(dòng)的網(wǎng)站上去了解學(xué)習(xí)怎么使用它訪(fǎng)問(wèn)mongodb。
    2015-01-01
  • nodejs+express搭建多人聊天室步驟

    nodejs+express搭建多人聊天室步驟

    本篇文章給大家詳細(xì)講解了nodejs+express搭建一個(gè)簡(jiǎn)易的多人聊天室的詳細(xì)步驟,有興趣的朋友學(xué)習(xí)下。
    2018-02-02
  • node異步方法的異步調(diào)用與同步調(diào)用實(shí)現(xiàn)方法示例

    node異步方法的異步調(diào)用與同步調(diào)用實(shí)現(xiàn)方法示例

    這篇文章主要介紹了node異步方法的異步調(diào)用與同步調(diào)用實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了node.js異步操作類(lèi)的封裝以及同步、異步兩種調(diào)用方式,需要的朋友可以參考下
    2023-05-05
  • nodejs和npm版本不匹配:ERROR:?npm?v9.5.1?is?known?not?to?run?on?Node.js

    nodejs和npm版本不匹配:ERROR:?npm?v9.5.1?is?known?not?to?run

    本文主要介紹了nodejs和npm版本不匹配:ERROR:?npm?v9.5.1?is?known?not?to?run?on?Node.js,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 一文帶你了解Node.js中的path模塊

    一文帶你了解Node.js中的path模塊

    Node.js和Python技術(shù)類(lèi)似,?都致力于能夠?qū)崿F(xiàn)跨平臺(tái)的通用代碼。?為此,針對(duì)路徑的拼接,?Node.js提供了path模塊,本文就來(lái)講講path模塊的使用
    2023-03-03

最新評(píng)論