nodejs非同步IO的實現

2022-03-05 20:34:44 字數 2100 閱讀 6795

nodejs的核心之一就是非阻塞的非同步io,於是想知道它是怎麼實現的,挖了下nodejs原始碼,找到些答案,在此跟大家分享下。首先,我用了一段js**test-fs-read.js做測試,**如下:

var path = require('path'), fs = require('fs'), filepath = path.join(__dirname, 'experiment.log'), fd = fs.opensync(filepath, 'r');  fs.read(fd, 12*1024*1024, 0, 'utf-8', function(err, str, bytesread) ); console.log('[main thread] execute operation after read');
這段**的非同步io操作就在fs.read的呼叫上,讀取的experiment.log是乙個12m的文字檔案,所謂的非同步,大家大概能想得到執行時會先列印

[main thread] execute operation after read

然後列印**函式中的

[main thread] execute read callback

但 大家也許還聽說過,nodejs是單執行緒的,那又是怎麼實現非同步io的呢?讀檔案操作是在**執行的呢?讀完又是怎麼呼叫**函式的呢?猜想讀文 件可能是在另乙個執行緒中完成的,讀完後通過事件通知nodejs執行**。為了一**竟,debug了一把nodejs和libeio原始碼,重新編譯後, 執行測試**node test-fs-read.js,輸出如下:

可以看到,nodejs的io操作是通過呼叫libeio庫完成的,debug從fs.read開始,js**經過v8編譯後,fs.read會呼叫node_file.cc中的read方法,測試**的執行經歷了以下步驟:

1 node_file.cc中的read方法呼叫libeio(eio.c)的eio_read, read請求被放入請求佇列req_queue中。

2 主線程建立了1個eio執行緒,此時主線程的read呼叫返回。

3 eio執行緒從req_queue中取出1個請求,開始執行read io

4 主線程繼續執行read呼叫後的其它操作。

5 主線程poll eio,從響應佇列res_queue取已經完成的請求,此時res_queue為空,主線程stop poll

6 eio執行緒完成了read io,read請求被放入響應佇列res_queue中,並且向主線程傳送libev事件want_poll(通過主線程初始化eio時提供的**函式)。

7 eio執行緒從req_queue中取下乙個請求,此時已經沒有請求。

8 主線程響應want_poll事件,從res_queue中取出1個請求,取出請求後res_queue變為空,主線程傳送done_poll事件。

9 主線程執行請求的callback函式。

還需要說明的是,當同時有多個io請求時,主線程會建立多個eio執行緒,以提高io請求的處理速度。

為了更清晰的看到nodejs的io執行過程,圖示如下,序號僅用來標示流程,與上述步驟序號並無對應關係。

最後總結幾條,不當之處還請大家指正。

1 nodejs通過libev事件得到io執行狀態,而不是輪詢,提高了cpu利用率。

2 雖然nodejs是單執行緒的,但它的io操作是多執行緒的,多個io請求會建立多個libeio執行緒(最多4個),使通常情況的io操作效能得到提高。

3 但是當io操作情況比較複雜的時候,有可能造成執行緒競爭狀態,導致io效能降低;而且libeio最多建立4個執行緒,當同時有大量io請求時,實際效能有 待測量。另外,由於每個io請求對應乙個libeio的資料結構,當同時有大量io操作駐留在系統中時候,會增加記憶體開銷。

4 libeio為了實現非同步io功能,帶來了額外的管理,當io資料量比較小的時候,整體效能不一定比同步io好。

1、node使用libeio實現非阻塞非同步檔案操作,但實際上libeio是通過多執行緒的方式,在標準的阻塞式io上模擬非阻塞非同步。

2、為什麼node沒有使用原生態的非同步io api(aio)?原因可能是為了實現跨平台的相容性(主要針對windows,具體參見: /group/nodejs/browse_thread/thread/aff97d25c59f6f2d)

3、libeio的4個執行緒限制是預設配置,可以對此配置進行修改

python實現自己的非同步IO等非同步操作

首先引用下廖雪峰老師 上的這部分介紹 協程,又稱微執行緒,纖程。英文名coroutine。協程的概念很早就提出來了,但直到最近幾年才在某些語言 如lua 中得到廣泛應用。子程式,或者稱為函式,在所有語言中都是層級呼叫,比如a呼叫b,b在執行過程中又呼叫了c,c執行完畢返回,b執行完畢返回,最後是a執...

《深入淺出nodejs》非同步i o筆記(1)

阻塞i o 呼叫之後一定要等到系統核心層面完成所有的操作,呼叫才會結束。eg 讀取檔案 核心在完成磁軌尋盤 讀取資料 複製資料到記憶體之後,呼叫才算結束。非阻塞i o 呼叫之後立即返回。作業系統將所有的輸入輸出裝置抽象為檔案。進行檔案操作時,通過檔案描述符進行管理,檔案描述符類似於應用程式與系統核心...

linux的非同步IO 使用signal實現中斷

include include include include include include include char buff 20 int mousefd 1 int ret 1 int flag 0 在函式內處理非同步通知事件 void func int sig else n sig mem...