1. 程式人生 > >Node.js入門:非同步IO

Node.js入門:非同步IO

非同步IO

    在作業系統中,程式執行的空間分為核心空間和使用者空間。我們常常提起的非同步I/O,其實質是使用者空間中的程式不用依賴核心空間中的I/O操作實際完成,即可進行後續任務。

同步IO的並行模式

  • 多執行緒單程序
    多執行緒的設計之處就是為了在共享的程式空間中,實現並行處理任務,從而達到充分利用CPU的效果。多執行緒的缺點在於執行時上下文交換的開銷較大,和狀態同步(鎖)的問題。同樣它也使得程式的編寫和呼叫複雜化。
  • 單執行緒多程序
    為了避免多執行緒造成的使用不便問題,有的語言選擇了單執行緒保持呼叫簡單化,採用啟動多程序的方式來達到充分利用CPU和提升總體的並行處理能力。它的缺點在於業務邏輯複雜時(涉及多個I/O呼叫),因為業務邏輯不能分佈到多個程序之間,事務處理時長要遠遠大於多執行緒模式。

非同步IO的必要性

    採用同步方式的程式要完成這兩個任務的時間總花銷會是m + n。但是如果是採用非同步方式的程式,在兩種I/O可以並行的狀況下(比如網路I/O與檔案I/O),時間開銷將會減小為max(m, n)。而當並行任務更多的時候,m + n + …與max(m, n, …)之間的孰優孰劣更是一目瞭然。Node.js天然地支援這種非同步I/O,這是眾多雲計算廠商對其青睞的根本原因。

作業系統對非同步I/O的支援

    非同步與非阻塞聽起來似乎是同一回事。從實際效果的角度說,非同步和非阻塞都達到了我們並行I/O的目的。但是從計算機核心I/O而言,非同步/同步和阻塞/非阻塞實際上時兩回事。
  • I/O的阻塞與非阻塞
    阻塞模式的I/O會造成應用程式等待,直到I/O完成。同時作業系統也支援將I/O操作設定為非阻塞模式,這時應用程式的呼叫將可能在沒有拿到真正資料時就立即返回了,為此應用程式需要多次呼叫才能確認I/O操作完全完成。
  • I/O的同步與非同步
    I/O的同步與異步出現在應用程式中。如果做阻塞I/O呼叫,應用程式等待呼叫的完成的過程就是一種同步狀況。相反,I/O為非阻塞模式時,應用程式則是非同步的。

非同步I/O與輪詢技術

    當進行非阻塞I/O呼叫時,要讀到完整的資料,應用程式需要進行多次輪詢,才能確保讀取資料完成,以進行下一步的操作。     輪詢技術的缺點在於應用程式要主動呼叫,會造成佔用較多CPU時間片,效能較為低下。現存的輪詢技術有以下這些:
  • read:通過重複呼叫來檢查I/O的狀態來完成完整資料讀取,效能也是最低的一種。
  • select:通過對檔案描述符上的事件狀態來進行判斷。
  • poll 
  • epoll 
  • pselect 
  • kqueue
    輪詢技術滿足了非同步I/O確保獲取完整資料的保證。但是對於應用程式而言,它仍然只能算時一種同步,因為應用程式仍然需要主動去判斷I/O的狀態,依舊花費了很多CPU時間來等待。

理想的非同步I/O模型

    理想的非同步I/O應該是應用程式發起非同步呼叫,而不需要進行輪詢,進而處理下一個任務,只需在I/O完成後通過訊號或是回撥將資料傳遞給應用程式即可。   

不同作業系統的非同步IO方案

  • Linux
    在Linux下存在一種這種方式,它原生提供了一種非同步非阻塞I/O方式(AIO)即是通過訊號或回撥來傳遞資料的。不幸的是,只有Linux下有這麼一種支援,而且還有缺陷(AIO僅支援核心I/O中的O_DIRECT方式讀取,導致無法利用系統快取.     另一種理想的非同步I/O是採用阻塞I/O,但加入多執行緒,將I/O操作分到多個執行緒上,利用執行緒之間的通訊來模擬非同步.     Linux平臺下沒有完美的非同步I/O支援。所幸的是,libev的作者Marc Alexander Lehmann重新實現了一個非同步I/O的庫:libeio。libeio實質依然是採用執行緒池與阻塞I/O模擬出來的非同步I/O。
  • Windows
    Windows有一種獨有的核心非同步IO方案:IOCP。IOCP的思路是真正的非同步I/O方案,呼叫非同步方法,然後等待I/O完成通知。IOCP內部依舊是通過執行緒實現,不同在於這些執行緒由系統核心接手管理。IOCP的非同步模型與Node.js的非同步呼叫模型已經十分近似。

Node.js的非同步IO方案

    由於Windows平臺和*nix平臺的差異,Node.js提供了libuv來作為抽象封裝層,使得所有平臺相容性的判斷都由這一層次來完成,保證上層的Node.js與下層的libeio/libev及IOCP之間各自獨立。Node.js在編譯期間會判斷平臺條件,選擇性編譯unix目錄或是win目錄下的原始檔到目標程式中。

Node.js的非同步IO模型

    Node.js的回撥函式究竟是如何被呼叫的?在檔案I/O這一塊與普通的業務邏輯的回撥函式不同在於它不是由我們自己的程式碼所觸發,而是系統呼叫結束後,由系統觸發的。     下面我們以最簡單的fs.open方法來作為例子,探索Node.js與底層之間是如何執行非同步I/O呼叫和回撥函式究竟是如何被呼叫執行的。
1 fs.open = function(path, flags, mode, callback) { 
2     callback = arguments[arguments.length - 1]; 
3     if (typeof(callback) !== 'function') { 
4         callback = noop;
5     }
6     mode = modeNum(mode, 438 /*=0666*/); 
7     binding.open(pathModule._makeLong(path), stringToFlags(flags), mode, callback); };

    fs.open的作用是根據指定路徑和引數,去開啟一個檔案,從而得到一個檔案描述符,是後續所有I/O操作的初始操作。

      在JavaScript層面上呼叫的fs.open方法最終都透過node_file.cc呼叫到了libuv中的uv_fs_open方法,這裡libuv作為封裝層,分別寫了兩個平臺下的程式碼實現,編譯之後,只會存在一種實現被呼叫。
  • 請求物件
    在uv_fs_open的呼叫過程中,Node.js建立了一個FSReqWrap請求物件。從JavaScript傳入的引數和當前方法都被封裝在這個請求物件中,其中回撥函式則被設定在這個物件的oncomplete_sym屬性上。
req_wrap->object_->Set(oncomplete_sym, callback);
    物件包裝完畢後,呼叫QueueUserWorkItem方法將這個FSReqWrap物件推入執行緒池中等待執行。
QueueUserWorkItem(&uv_fs_thread_proc, req, WT_EXECUTELONGFUNCTION)
    QueueUserWorkItem接受三個引數,第一個是要執行的方法,第二個是方法的上下文,第三個是執行的標誌。當執行緒池中有可用執行緒的時候呼叫uv_fs_thread_proc方法執行。該方法會根據傳入的型別呼叫相應的底層函式,以uv_fs_open 為例,實際會呼叫到fs__open方法。呼叫完畢之後,會將獲取的結果設定在req->result上。然後呼叫PostQueuedCompletionStatus通知我們的IOCP物件操作已經完成。
PostQueuedCompletionStatus((loop)->iocp, 0, 0, &((req)->overlapped))
    PostQueuedCompletionStatus方法的作用是向建立的IOCP上相關的執行緒通訊,執行緒根據執行狀況和傳入的引數判定退出。至此,由JavaScript層面發起的非同步呼叫第一階段就此結束。
  • 事件迴圈
    在呼叫uv_fs_open方法的過程中實際上應用到了事件迴圈。以在Windows平臺下的實現中,啟動Node.js時,便建立了一個基於IOCP的事件迴圈loop,並一直處於執行狀態。
uv_run(uv_default_loop());
    每次迴圈中,它會呼叫IOCP相關的GetQueuedCompletionStatus方法檢查是否執行緒池中有執行完的請求,如果存在,poll操作會將請求物件加入到loop的pending_reqs_tail屬性上。另一邊這個迴圈也會不斷檢查loop物件上的pending_reqs_tail引用,如果有可用的請求物件,就取出請求物件的result屬性作為結果傳遞給oncomplete_sym執行,以此達到呼叫JavaScript中傳入的回撥函式的目的。至此,整個非同步I/O的流程完成結束。     其流程如下:       事件迴圈和請求物件構成了Node.js的非同步I/O模型的兩個基本元素,這也是典型的消費者生產者場景。在Windows下通過IOCP的GetQueuedCompletionStatus、PostQueuedCompletionStatus、QueueUserWorkItem方法與事件迴圈實。對於*nix平臺下,這個流程的不同之處在與實現這些功能的方法是由libeio和libev提供。

相關推薦

Node.js入門非同步IO

非同步IO     在作業系統中,程式執行的空間分為核心空間和使用者空間。我們常常提起的非同步I/O,其實質是使用者空間中的程式不用依賴核心空間中的I/O操作實際完成,即可進行後續任務。 同步IO的並行模式 多執行緒單程序     多執行緒的設計之處就是為了在共享的程式空間中,實現並行處理

Node.js入門模組機制

**CommonJS規範 ** 早在Netscape誕生不久後,JavaScript就一直在探索本地程式設計的路,Rhino是其代表產物。無奈那時服務端JavaScript走的路均是參考眾多伺服器端語言來實現的,在這樣的背景之下,一沒有特色,二沒有實用價值。但是隨著JavaScript在前端的應

Node.js入門前後端模組的異同

    通常有一些模組可以同時適用於前後端,但是在瀏覽器端通過script標籤的載入JavaScript檔案的方式與Node.js不同。Node.js在載入到最終的執行中,進行了包裝,使得每個檔案中的變數天然的形成在一個閉包之中,不會汙染全域性變數。而瀏覽器端則通常是裸露的JavaScript程式碼片段。所以

Node.js入門包結構

    JavaScript缺少包結構。CommonJS致力於改變這種現狀,於是定義了包的結構規範(http://wiki.commonjs.org/wiki/Packages/1.0 )。而NPM的出現則是為了在CommonJS規範的基礎上,實現解決包的安裝解除安裝,依賴管理,版本管理等問題。require

Node.js入門Hello World

  馬上開始我們第一個Node.js應用:“Hello World”。開啟你的編輯器,建立一個hello.js檔案。編寫程式碼儲存該檔案,並通過Node.js來執行。 控制檯輸出 1 console.log('hello, nodejs.') ; Web輸出 1

Node.js入門Node.js&NPM的安裝與配置

Node.js安裝與配置      Node.js已經誕生兩年有餘,由於一直處於快速開發中,過去的一些安裝配置介紹多數針對0.4.x版本而言的,並非適合最新的0.6.x的版本情況了,對此,我們將在0.6.x的版本上介紹Node.js的安裝和配置。(本文一律以0.6.1為例,0.6的其餘版本,只需替換版本號即

Node.js入門事件機制

Evented I/O for V8 JavaScript     基於V8引擎實現的事件驅動IO。 事件機制的實現     Node.js中大部分的模組,都繼承自Event模組(http://nodejs.org/docs/latest/api/events.html )。Event模組(ev

Node.js入門檔案查詢機制

檔案查詢流程圖 從檔案模組快取中載入     儘管原生模組與檔案模組的優先順序不同,但是都不會優先於從檔案模組的快取中載入已經存在的模組。 從原生模組載入     原生模組的優先順序僅次於檔案模組快取的優先順序。require方法在解析檔名之後,優先檢查模組是否在原生模組列

(原創)node.js入門之一express簡單伺服器搭建-Mac環境開發

0:開篇廢話 好久沒來記錄點東西了,以前記錄的都是一些解決小問題的程式碼片段,只能算是當記事本來用的吧。 換了工作,好像沒那麼多程式碼要寫了,那就自己找點事做,於是重新翻出了nodejs,以前是在主程的搭建環境下,寫一些介面給我的iOS前

Node.js入門以及第一個helloworld程序

目錄 rip 工作 直播 需要 減少 web容器 用戶 長連接 1、概念:簡單的說 Node.js 就是運行在服務端的 JavaScript。學之前需要明白Node.js是無法挑戰jsp、php或者asp這種老牌網站的地位的,是永遠不會出現在證券、金融這種領域的。node.

Node.js入門》Windows 7下Node.js Web開發環境搭建筆記

基於 方法 一位 實時 ibm cal 項目 直觀 ear 近期想嘗試一下在IBM Bluemix上使用Node.js創建Web應用程序。所以須要在本地搭建Node.js Web的開發測試環境。這裏講的是Windows下的搭建方法,使用CentOS 的小夥伴請參考:《No

Node.js入門

js代碼 roc 簡單 本地 node span server -s host Node的安裝就不說了,流程見http://www.runoob.com/nodejs/nodejs-install-setup.html。直接來做一個簡單的web服務器 首先輸入並保存一個js

node js實戰帶數據庫,加密的註冊登錄表單

settings else input 是否 rip dig code setting 個人 demo 註冊效果: 登陸效果: 數據庫截圖: 數據庫操作 db.js //這個模塊裏面封裝了所有對數據庫的常用操作 var MongoClient =

Node.js入門到企業Web開發中的應用

實戰 tput 統一 sse 介紹 有用 enc oba 入門到 第1章 課程內容介紹主要介紹為什麽我們錄制本次課程、課程包含的主要內容。1-1 導學1-2 課程介紹 第2章 NodeJS 是什麽,為什麽偏愛NodeJS?在一切課程課程內容開始之前先了解一下 NodeJS

易學筆記-第2部分 Node.js入門指南/第5章 Node.js在幣圈流行麼

第2部分 Node.js入門指南/第5章 Node.js在幣圈流行麼/5.1 Node.js在開源社群很流行 Node.js在開源社群很流行 概念:JavaScript大部分專案都是建立在Node.js平臺之上的 在Github上專案採用的語言統計,JavaScr

Node.js入門學習筆記(1)

node.js筆記(1) 前端小白 自己打算做個微信小程式,剛好學習一下node.js,準備用node搭建一個簡單的後臺。寫部落格記錄一下學習進度,另一方面加強對新知識的理解。 主要學習途徑 一、node安裝 之前安裝過,這裡簡單記錄一下 安裝包地址 檢查n

Node js入門 Windows 7下Node js Web開發環境搭建筆記

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Node.js Streams你需要知道的一切

Node.js Streams:你需要知道的一切 影象來源 Node.js流以難以使用而聞名,甚至更難理解。好吧,我有個好訊息 - 不再是這樣了。 多年來,開發人員在那裡建立了許多軟體包,其唯一目的是簡化流程。但在本文中,我將重點介紹本機Node.js流API。 “Str

原始碼--Node.js 探祕初識單執行緒的 Node.js

  -- 高階理解 Nodejs, 從原始碼方向理解   // Node.js 探祕:初識單執行緒的 Node.js http://taobaofed.org/blog/2015/10/29/deep-into-node-1/ // 深入理解 Nod

Node.js入門介紹

非同步和同步:同步和非同步通常用來形容一次方法呼叫。同步方法呼叫一旦開始,呼叫者必須等到方法呼叫返回後,才能繼續後續的行為。非同步方法呼叫更像一個訊息傳遞,一旦開始,方法呼叫就會立即返回,呼叫者就可以繼續後續的操作。但此時,非同步方法通常會在另外一個執行緒中,“真實”地執行著。整個過程,不會阻礙呼叫者的工作。