深刻淺出node(3) 異步I/O

這篇主要整理深刻淺出Node.js第三章 異步I/Ojavascript

一) 異步I/O的緣由 java

二)異步I/O實現現狀node

  2.1 異步I/O與非阻塞I/O瀏覽器

  2.2 輪詢服務器

  2.3 理想的非阻塞異步I/O多線程

  2.4 現實的異步I/O併發

三)Node的異步I/O異步

  3.1 事件循環ide

  3.2 理解異步回調函數的執行過程函數

    3.2.1 基礎

    3.2.2 過程

四)事件驅動與高性能服務器

 

一) 異步I/O的緣由  異步I/O主要有如下兩點的需求

  • 用戶體驗  同步的模式下,在瀏覽器中等待服務端數據的過程當中,瀏覽器頁面會鎖死   同時請求A B   同步的狀況下時間爲 time(A) + time(B)  異步的狀況下是 時間爲 Max(time(A),time(B))  而且當請求不斷增加的時候,帶來的差別更大
  • 異步I/O能更好的分配資源 異步I/O不會阻塞後續的運算,將原有的等待I/O的時間分配給其他的任務去執行

二) 異步I/O實現現狀

  2.1 異步I/O與非阻塞I/O   對操做系統的內核來講只存在阻塞I/O和非阻塞I/O (我對書中這部分的理解是這樣的 好比異步I/O是node爲咱們提供的一層API接口,讓咱們能經過非阻塞的形式去I/O)  

  操做系統對輸入輸出設備抽象成文件,內核在進行文件的I/O操做的時候,經過文件描述符進行管理,也就是應用程序須要I/O的時候,須要先打開文件描述符,在根據文件描述符去實現文件的讀寫  非阻塞I/O和阻塞I/O的區別主要在於阻塞I/O直接完成整個數據獲取的流程,非阻塞I/O返回的是文件描述符,當須要獲取數據的時候,在經過文件描述符去讀取數據

  2.2 輪詢 輪詢技術主要爲了解決非阻塞I/O什麼時候完成完整的I/O而出現的  下面是輪詢技術的演變過程

  • read 它經過重複檢查I/O的狀態來完成完整數據的讀取 在獲得數據前 CPU一直處於等待的狀態

  • select 它在read的基礎上進行了一些改進,經過對文件描述符的事件狀態進行判斷來完成數據的I/O  它採用一個1024長度的數據來存儲狀態,因此它只能同時檢測1024個文件描述符

  • poll 它是在select基礎上進行的改進,它採用鏈表的方式存儲文件描述符,避免了數據的限制,可是在文件描述符不少的時候,性能有所降低

 

  • epoll  該方案是Linux下最高的事件通知機制 當沒有I/O事件的時候,它會休眠(觀察者),充分的利用了事件通知,執行回調來代替遍歷查詢 不會浪費CPU 因此執行的效率更高

  2.3 理想的非阻塞異步I/O  理想的應該是由應用程序發起異步方法,不須要遍歷或者事件喚醒等方式輪詢,直接進入下一個任務,在I/O完成後經過信號或者回調的方式將數據傳送給應用程序

  2.4 現實的異步I/O

三) Node中的異步I/O

  3.1 事件循環  在進程啓動的時候,Node會建立一個相似於while(true)的循環,每執行一次循環體稱爲Tick,每一次Tick的時候會查看是否有事件等待處理,若是有就取出事件而且執行相應的回調函數,沒有的話就退出進程  事件循環是典型的生產者消費者模型 在Windows下這個循環基於IOCP,而在*nix基於多線程建立

 3.2 理解異步回調的執行過程

  3.2.1 基礎 

  • 請求對象   從javascript發起調用到內核執行完I/O操做的過渡過程當中的中間產物 全部的狀態都保存在這個對象,包括送入線程池等待執行以及I/O操做完畢後的回調處理 
  •  Node中的經典調用模式 javascript調用Node的核心模塊,核心模塊調用C++內建模塊 內建模塊經過libuv(跨平臺)進行系統調用

  3.2.2 過程  

  1. 從javascript到內建模塊的調用過程當中會建立一個請求對象,將javascript層傳入的參數和方法都封裝到這個請求對象上,回調函數會被設置到這個請求對象的oncomplete_sym上 ,供後續的調用,而後將這個請求對象推入線程池中等待執行,此時javascript的調用當即返回(底層的I/O仍然多是阻塞或者是非阻塞的)
  2. 線程池中的I/O執行完畢後,會將結果存儲在請求對象的result上,此時它會通知自己的執行狀態已經完畢,而且將線程歸還給線程池
  3. 在每次的Tick中,檢查是否有執行完的請求,若是有將請求對象加入I/O觀察者的隊列,而且當作事件進行處理
  4. I/O觀察者會取出事件回調函數而且將result當作參數傳遞給回調函數執行,這樣就達到了執行回調函數的目的  

四)事件驅動與高性能服務器

  幾種經典的服務器模型

  • 同步式 一次只能處理一個請求,而且其他的請求都處於等待的狀態
  • 每進程/每請求 爲每一個請求啓動一個進程,可是不具有擴展性,由於系統的資源只有那麼多
  • 每線程/每請求 爲每一個請求啓動一個線程來處理,可是線程佔用必定的內存,大併發到來的時候,會形成系統運行緩慢

 Node的高性能正是由於它的事件驅動模式.

相關文章
相關標籤/搜索