node中异步IO的理解
解釋性語言和編譯型語言的區別:
計算器不能直接的理解高級語言,只能理解機器語言,所以必須把高級語言翻譯為機器語言,翻譯的方式有兩種,一個是編譯,一個是解釋。
解釋性語言的程序不需要編譯,它是在運行程序的時候進行翻譯,比如java,專門有一個解釋器可以直接執行Java程序,每一個語句都是執行的時候才能翻譯,編譯型就是編譯的時候直接編譯成機器可以執行的,編譯和執行時分開的,但是不能跨平臺。因為翻譯只做了一次,運行的時候不需要再去翻譯,所以編譯型語言的程序執行效率高。
對于解釋性語言,程序運行時的控制權在解釋器而不在于程序,對于編譯型語言程序運行時的控制權在程序。
進程的前臺運行和后臺運行
后臺進程是一直運行的服務端程序,又稱為守護進程,通常是在系統后臺運行,沒有控制終端,不與前臺交互,一般作為系統服務使用。其稱為后臺進程的原因大部分是因為它沒有控制端,無法和前臺的用戶交互。
相對應的前臺進程,就是我們在終端中開啟的進程,例如我們在終端中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中的線程有什么不同?
轉載于:https://www.cnblogs.com/blackgan/p/9296667.html
總結
以上是生活随笔為你收集整理的node中异步IO的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AnalyticDB - 分析型数据库
- 下一篇: Python3 嵌套函数