netpoll
Go 的 netpoll 是 Go 語言運行時(runtime)實現的核心 I/O 多路復用機制,它使得 Go 能夠以簡潔的同步編程模型(每個連接一個 Goroutine)實現高性能的網絡服務。其本質是將操作系統底層的 I/O 多路復用系統調用(如 Linux 的 epoll)與 Go 的 Goroutine 調度器深度結合。
Netpoll與原生GoNet對比
- Goroutine數目 Go Net:一個Goroutine下只有一個連接。
NetPoll:一個Goroutine下有多個連接。
- goroutine 上下文切換調度 壓力 Go Net: 高並發時 切換壓力大。 因為 GoNet 一個鏈接對應一個goroutine,goroutine數目多時切換頻繁。
NetPoll:高並發時 切換壓力 小。 因為 NetPoll 多個鏈接共用一個goroutine,切換次數少。
- 內存消耗: Go Net: 內存消耗與連接數正相關,高並發時可能因Goroutine數量爆炸導致內存壓力
NetPoll:預先分配緩沖區,創建緩沖區池。
- 觸發方式 Go Net:使用 邊緣觸發 ET。一次讀完數據,實現簡單。
NetPoll:使用 水平觸發 LT。不需要預分配足夠大的內存做數據緩沖區。
- 是否支持內核和用戶層共用buff池,少拷貝一次數據。 Go Net:不支持。
NetPoll:支持。管理一個Buffer池直接交給用戶,少拷貝一次。
- 適用場景 Go Net:低並發簡單場景
NetPoll:高並發低延遲場景
netpoll 設計思路
基本架構 原生網絡庫 基於epoll lt模式 開發,基本架構如下圖所示:

goroutine的使用 存在一個 poll對象池,每個poll對象帶有一個epoll,和單獨對應一個 goroutine。 goroutine數目和 poll對象數目一致,每個poll對象可以監聽多個 文件描述符fd
IO讀寫邏輯
- 每個poll對象開啟一個goroutine來不斷輪詢當前epoll上的可讀可寫等事件
- 每個epoll會關聯多個fd,每個fd關聯一個 Buffer。
- 當從 fd 監聽到有可讀事件後,會把數據讀到 Buffer裡。
- 不斷輪詢處理 Buffer 的數據,當發現數據讀完整之後,通知後面的處理邏輯的協程池 GoPoll去執行
- 與內核的系統調用交互完全由netpoll控制,用戶層對 Conn 的讀寫都只是在操作共用的Buffer而已。
優劣勢 優勢: 支持高並發能力更強。
- (1) 輪詢處理Buffer的數據,不存在數據得不到處理的情況。
- (2) 一個goroutine對應多個連接,即使連接非常多,資源調度切換上的開銷也不大。
- (3) 支持用戶和內核共享buff,減少一次數據拷貝操作,提升效率。
劣勢:需要佔用更多的內存。
