面試官:談談你對IO多路復用的理解?
“IO 多路復用”是編程中常見的技術詞匯,使用這種技術的框架有很多,如,Redis、Kafka、Netty、Nginx 中都用到了此技術。那問題來了,什么是 IO 多路復用?它的具體實現技術有哪些?這些技術之間有什么區別?今天我們就來簡單的探討一下。
1.什么是IO多路復用?
IO 多路復用技術是一種允許單個線程管理多個網絡連接的技術,它使得服務器能夠高效地處理大量的并發連接而不需要為每個連接創建一個獨立的線程或進程。
圖片
想象如果客戶端有成千上萬個的情況下,那么非 IO 多路復用就會有成千上萬個線程,那么就會發生 IO 過度爭搶和多線程切換的問題,因為 CPU 資源只有幾個,而要執行的線程卻有成千上萬個。
2.IO多路復用技術實現
常用的 IO 多路復用實現技術有:select、poll、epoll 和 kqueue 等,它們的具體介紹如下。
2.1 select
- 特點:select 是最早出現的一種多路復用 I/O 模型,幾乎在所有平臺上都有支持。它通過一個調用來監視多個文件描述符,等待其中任何一個變為可讀或可寫狀態。
- 局限性:
文件描述符數量受限:通常限制為 1024 個,可以通過修改系統參數來增加這個限制,但這樣做會消耗更多的系統資源。
效率低下:每次調用 select 都需要將文件描述符列表復制到內核,檢查完后又需要復制回用戶空間,這對于大量文件描述符來說效率很低。
不支持邊緣觸發模式:只支持水平觸發模式。
邊緣觸發模式 VS 水平觸發模式
- 邊緣觸發模式:當一個文件描述符從不可讀(或不可寫)變為可讀(或可寫)時,內核僅通知應用程序一次。如果應用程序未能立即處理完所有可用的數據(例如,緩沖區中的數據未完全讀?。?,那么即使文件描述符仍然是可讀的,內核也不會再次通知應用程序,直到該文件描述符的狀態再次發生變化(例如,從可讀變為不可讀,再變回可讀)。
優點:減少了系統調用次數,提高了效率,特別適合于大數據量傳輸的場景。
缺點:要求應用程序必須在接收到事件后盡可能多地讀取或寫入數據,否則可能會錯過后續的數據。因此,邊緣觸發模式對編程的要求較高,需要更加小心地處理。
- 水平觸發模式:在水平觸發模式下,只要文件描述符處于可讀(或可寫)狀態,無論之前是否已經通知過,內核都會持續通知應用程序。這意味著,如果應用程序未能一次性處理完所有數據,只要文件描述符仍然處于可讀或可寫狀態,內核就會繼續發送通知。
- 優點:編程較為簡單,因為即使錯過了某個事件的通知,只要文件描述符的狀態沒有改變,應用程序仍然有機會在下一次輪詢時接收到同樣的事件。
- 缺點:可能造成更多的系統調用,因為即使數據已經被部分處理,內核仍然會不斷地通知應用程序,這可能導致效率降低。
2.2 poll
- 特點:poll 在功能上與 select 非常相似,但沒有文件描述符數量的限制。poll 使用一個 pollfd 結構體數組來表示要監聽的文件描述符集合。
- 局限性:雖然解決了 select 的文件描述符數量限制問題,但在性能上仍然存在類似 select 的問題,即每次調用都需要復制文件描述符列表到內核,并且返回時也需要復制回用戶空間。
2.3 epoll
- 特點:epoll 是 Linux 特有的高效 IO 多路復用技術,它克服了 select 和 poll 的所有缺點。epoll 使用三個系統調用來管理文件描述符:epoll_create 創建一個 epoll 實例,epoll_ctl 添加/刪除需要監聽的文件描述符,epoll_wait 等待事件的發生。
- 優勢:
無數量限制:沒有文件描述符數量限制。
高效:只有活躍的文件描述符才會被傳遞給用戶空間,減少了不必要的復制操作。
功能強大:支持邊緣觸發和水平觸發兩種工作模式。
2.4 kqueue
- 特點:kqueue 是 FreeBSD 操作系統引入的一種 IO 多路復用技術,后來也被 Mac OS X 和其他基于 BSD 的操作系統采用。kqueue 可以同時處理多種類型的事件,包括但不限于文件描述符事件、信號事件等。
- 優勢:
功能更強大:不僅支持文件描述符的事件通知,還能處理其他類型的事件。
性能優秀:與 epoll 類似,只有活躍的文件描述符才會被處理,從而提高了效率。
3.區別對比
select、poll、epoll 和 kqueue 之間的區別如下:
技術名稱 | 支持平臺 | 連接數限制 | IO效率 | 數據拷貝方式 |
select | 跨平臺 | 默認1024 | O(N) | 每次調用都拷貝 |
poll | 跨平臺 | 無 | O(N) | 每次調用都拷貝 |
epoll | Linux 特有 | 無 | O(1) | 僅在 epoll_ctl 時拷貝 |
kqueue | MacOS、FreeBSD 等 | 無 | O(1) | 具體實現方式可能因系統而異,但通常也是高效的。 |
課后思考
什么叫做“文件描述符”?IO 多路復用為什么要進行“數據拷貝”?


































