node中異步IO的理解

解釋性語言和編譯型語言的區別:

計算器不能直接的理解高級語言,只能理解機器語言,因此必須把高級語言翻譯爲機器語言,翻譯的方式有兩種,一個是編譯,一個是解釋。java

解釋性語言的程序不須要編譯,它是在運行程序的時候進行翻譯,好比java,專門有一個解釋器能夠直接執行Java程序,每個語句都是執行的時候才能翻譯,編譯型就是編譯的時候直接編譯成機器能夠執行的,編譯和執行時分開的,可是不能跨平臺。由於翻譯只作了一次,運行的時候不須要再去翻譯,因此編譯型語言的程序執行效率高。node

對於解釋性語言,程序運行時的控制權在解釋器而不在於程序,對於編譯型語言程序運行時的控制權在程序。web

進程的前臺運行和後臺運行

後臺進程是一直運行的服務端程序,又稱爲守護進程,一般是在系統後臺運行,沒有控制終端,不與前臺交互,通常做爲系統服務使用。其稱爲後臺進程的緣由大部分是由於它沒有控制端,沒法和前臺的用戶交互。npm

相對應的前臺進程,就是咱們在終端中開啓的進程,例如咱們在終端中npm run server.js啓動一個webServer,此時啓動的進程就是前臺進程,當你把當前的命令行終端進行關閉了以後,該進程也便被殺死了。緩存

node中的阻塞/非阻塞IO和同步/異步IO

表面上來看,這兩組的概念都差很少,阻塞/非阻塞IO,是操做系統內核對於IO的兩種處理方式,對於阻塞IO,好比讀取文件,操做系統在讀取完文件以後,纔會給應用程序返回結果,這一段過程呢,應用程序在等待操做系統的回覆,是爲應用層面的同步IO。異步

對於非阻塞IO,操做系統在接收到應用程序對於讀取文件的請求時,當即返回給應用程序一個結果,可是應用程序怎麼知道操做系統完成了IO操做呢?這時候應用程序就會對操做系統發起詢問(你到底好了沒有?人家都快急死了),發起詢問的方法又通過好幾種演變,好比read、poll、epoll等,中間多的無非就是根據文件描述符減小詢問的次數,整體上來講這種方式很差。並不能達到咱們理想的異步IO。函數

那麼從應用程序方面來將,咱們指望的異步IO,就是應用程序進行了IO操做以後,再也不須要操心操做系統何時返回,去執行下邊的代碼就好了,當操做執行完了以後呢,直接給應用程序發信息告訴他就好了。Linux系統下原生提供了一種AIO是經過信號或者回調來傳遞數據的,這個AIO就是咱們的理想的異步IO。可是不幸的是只有Linux中有,並且沒法利用系統緩存。操作系統

node(單線程)中對於*nix平臺而言,採用的是線程池+epoll異步IO模擬實現應用程序層面的異步IO,主線程進行執行程序,碰到咱們異步IO調用時,將改異步IO分配給線程池中的某一個線程,而後就變成了線程池中的某個線程和操做系統的阻塞IO進行IO操做,當IO線程接收到操做系統的阻塞IO執行的返回結果以後,IO線程再發送時間給主線程。命令行

node中對於window平臺而言,是依靠於IOCP來實現的,其內部仍然是線程池原理,不一樣之處在於這些線程池由系統內核接手管理。線程

node中對於異步IO的實現:

對於異步IO的實現,其中有幾個組成部分:事件循環、觀察者、請求對象

事件循環是node中的一種執行機制,這種機制是回調執行的基礎部分,它保證了咱們的回調函數可以被執行。

觀察者是暴露回調函數的窗口,若是總體的場景爲飲料工廠的話,咱們的瓶子就是咱們的回調函數,事件循環就是傳送帶在那一直轉,而觀察者就是瓶子就如機器的入口,機器就是咱們的應用程序。因此應用程序從觀察者這裏獲取事件,應用程序詢問觀察者是否還有事件。

請求對象,是應用程序封裝的一個對象,裏邊包含了要作的IO操做類型,以及回調函數。

總體流程就是,異步調用開始以後,應用程序封裝一個請求對象,送入咱們的線程池中的某個線程,該線程和操做系統的非阻塞IO經過epoll機制進行工做,這其中,會有觀察者在線程池中進行檢查,當某個線程的IO操做完成以後,觀察者會將回調函數(封裝在請求對象中的)放在事件循環上(上段提到的傳送帶),而後主線程調用回調函數。

參考:《深刻淺出Node.js》
問題思考:

  • 操做系統的線程與CPU中的線程有什麼不一樣?
相關文章
相關標籤/搜索