bio每次一個進程專門為了等一個 socket 上的數據就得被從 CPU 上拿下來。然後再換上另一個進程。等到數據 ready 了,睡眠的進程又會被喚醒。總共兩次進程上下文切換開銷
1.進程在 recv 的時候大概率會被阻塞掉,導致一次進程切換
2.當連接上數據就緒的時候進程又會被喚醒,又是一次進程切換
3.一個進程同時只能等待一條連接,如果有很多併發,則需要很多進程

若要支持超大 fd,需手動修改 FD_SETSIZE 並重新編譯,select可以突破1024上限https://elixir.bootlin.com/linux/v3.13.11/source/fs/select.c#L547

io_uring 是 Linux 5.1+ 引入的新一代異步 IO 框架,其事件通知支持 “被動喚醒”,用户進程無需主動調用系統調用查詢:
核心機制:
io_uring 有兩個核心的共享內存隊列(用户態 / 內核態直接映射,無需拷貝):
提交隊列(SQ):用户態向內核提交 IO 請求;
完成隊列(CQ):內核將完成事件主動寫入該隊列,用户態直接讀取。
被動通知流程:
用户進程通過 io_uring_setup 創建 io_uring 實例,映射 SQ/CQ 隊列到用户態內存;
通過 io_uring_enter 提交異步請求(或直接寫 SQ 隊列,無需系統調用);
內核自動完成數據準備 + 拷貝,完成後主動將事件寫入 CQ 隊列;
用户進程可以通過兩種方式獲取事件:
被動喚醒:調用 io_uring_wait_cqe 阻塞等待事件(內核有事件時主動喚醒線程,本質是 “內核推送給用户”);
主動查詢:直接輪詢 CQ 隊列的 head/tail 指針(無需系統調用,直接讀共享內存)。
核心特點:
無需主動調用類似 io_getevents 的系統調用 ——內核主動將事件寫入用户態共享內存的 CQ 隊列;
共享內存隊列的設計,讓事件通知的開銷幾乎為 0(無系統調用、無數據拷貝);
io_uring_wait_cqe 是阻塞等待,但屬於 “被動喚醒”,而非 “主動查詢”。