Asynchronous / Non-Blocking I/O
被說要多唸點書 QQ
在某次經驗中被說要多唸點書,所以整理一下 Asynchronous 跟 Non-Blocking I/O 的特性。
I/O
在 Unux / Linux 的環境中,I/O 都是針對一個 File Descriptor 操作,可能針對檔案、網路封包等 I/O 來讀寫檔案。根據讀/寫狀態可以分為 Blocking/Non-Blocking 與 Synchronous/Asynchronous 共四種。
Blocking I/O
在 OS 系統中通常提供的基本 I/O 會是 Blocking I/O:也就是針對一個 FD 做讀/寫時,就會需要等到 I/O 完成才會進行下一個步驟,當然 OS 可能會發送一個 Interrupt 中斷這個 I/O。因為依序執行且會等待 I/O 結束才會進行下一個步驟,對於較慢 I/O 的環境 (e.g. 網路環境) 就會讓 process 等待而浪費資源。
Non-Blocking I/O
跟 Blocking 相反的,Non-Blocking I/O 代表每一次 I/O 操作都會盡可能回覆而不讓 process 等待 I/O。 在 C 的世界中可以透過 fcntl 來修改 fd 的屬性:利用 O_NONBLOCK 讓 I/O 變成 Non-Blocking 模式 。在這個模式下,kernel 會盡其所能的 I/O,但即使沒有資料出現也會立即回傳。當沒有資料讀/寫則會標記 EAGAIN 。
fcntl(fd, F_SETFD, O_NONBLOCK);
while (0 != (tmp = read(fd, buff, sizeof(buff)))) {
if (-1 == tmp) {
switch (errno) {
case EAGAIN:
break;
default:
fprintf(stderr, "error - %s\n", strerror(errno));
goto END;
break;
}
continue;
}
len += tmp;
fprintf(stdout, "read : %zu bytes\n", tmp);
}
Asynchronous - Blocking I/O
這是同事推薦的 文章 提到關於 Asynchronous I/O 的 的特性:裡面提到 select 是一種 multiplexing I/O 的概念。這代表即使在另一個 thread 正在 I/O 也不會影響主 thread 的運作。同時, I/O 函數也會在呼叫時 Blocking 直到有任何一個 I/O 可以操作。
透過 OS 提供的 system call 來做到多 FD 同時操作 I/O 的概念, select 就可以在 user-space 一次監控多個 FD 並當有一個或多個 FD 可以 I/O 時,則會回傳可 I/O 的 FD 數量。另外還可設定 timeout 參數來更進一步做到 Non-Blocking I/O,也就是當 timeout 發生時,則會回傳 0 並立即結束。
Asynchronous - Non-Blocking I/O
Asynchronous I/O 則是另一種 Non-Blocking I/O 的特性:當呼叫一個 Asynchronous / Non-Blocking I/O 一樣立即結束並執行下一個指令。但跟 Non-Blocking I/O 不一樣的,Asynchronous I/O 會註冊一個 callback function 來執行 I/O 結束後的操作。