亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Node.js異步I/O學習筆記

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

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

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

1. 基本概念

“異步”與“非阻塞”聽起來似乎是一回事,從實際效果而言,這兩者都達到了并行的目的。但是從計算機內核I/O而言,只有兩種方式:阻塞與非阻塞。因此異步/同步和阻塞/非阻塞實際上是兩回事。

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

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

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

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

輪詢滿足了非阻塞I/O確保獲取完整數(shù)據(jù)的需求,但對于應用程序而言,它仍然只能算作一種同步,因為依然需要等待I/O完全返回。等待期間,CPU要么用于遍歷文件描述符的狀態(tài),要么用于休眠等待事件發(fā)生。

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

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

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

2. Node的異步I/O

2.1 事件循環(huán)

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

2.2 觀察者

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

2.3 請求對象

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

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

2.4 執(zhí)行回調

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

3. 非I/O的異步API

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

3.1 定時器API

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

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

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

復制代碼 代碼如下:

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

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

此外還有一個setImmediate()方法和上述方法類似,都是將回調函數(shù)延遲執(zhí)行。不過前者的優(yōu)先級要比后者高,這是因為事件循環(huán)對觀察者的檢查是有先后順序的。另外,前者的回調函數(shù)保存在一個數(shù)組中,每輪Tick會將數(shù)組中的所有回調函數(shù)全部執(zhí)行完;后者結果保存在鏈表中,每輪Tick只會執(zhí)行一個回調函數(shù)。

4. 事件驅動與高性能服務器

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

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

著名的Apache采用的就是每線程/每請求的形式,這也是它難以應對高并發(fā)的原因。Node通過事件驅動方式處理請求,可以省掉創(chuàng)建和銷毀線程的開銷,同時操作系統(tǒng)在調度任務時因為線程較少,上下文切換的代價也很低。即使在大量連接的情況下,Node也能有條不紊地處理請求。

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

相關文章

  • node.js中的console.warn方法使用說明

    node.js中的console.warn方法使用說明

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

    Nodejs Buffer的使用及Stream流和事件機制詳解

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

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

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

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

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

    用nodejs的實現(xiàn)原理和搭建服務器(動態(tài))

    下面小編就為大家?guī)硪黄胣odejs的實現(xiàn)原理和搭建服務器(動態(tài))。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • NodeJS學習筆記之MongoDB模塊

    NodeJS學習筆記之MongoDB模塊

    nodejs是個強大的平臺,有基本功能,而且可以掛很多模塊。我們現(xiàn)在需要和mongodb連接的驅動,就類似比如mysql的java驅動一樣。nodejs有好幾個mongodb的第三方驅動。和jdbc不一樣,沒有標準。所以需要到驅動的網(wǎng)站上去了解學習怎么使用它訪問mongodb。
    2015-01-01
  • nodejs+express搭建多人聊天室步驟

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

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

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

    這篇文章主要介紹了node異步方法的異步調用與同步調用實現(xiàn)方法,結合實例形式分析了node.js異步操作類的封裝以及同步、異步兩種調用方式,需要的朋友可以參考下
    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,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-06-06
  • 一文帶你了解Node.js中的path模塊

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

    Node.js和Python技術類似,?都致力于能夠實現(xiàn)跨平臺的通用代碼。?為此,針對路徑的拼接,?Node.js提供了path模塊,本文就來講講path模塊的使用
    2023-03-03

最新評論