高效能網路框架筆記二(阻塞與非阻塞、同步與非同步)
在高效能網路架構筆記一中,我們聊完了網路資料的接收和傳送。本章我們談一下易混淆的概念:阻塞與同步,非阻塞與非同步。
經過前面對網路資料包接收流程的介紹,在這裡我們可以將整個流程總結為兩個階段:
- 資料準備階段:在這個階段,網路資料包到達網絡卡,通過DMA的方式將資料包拷貝到記憶體中,然後經過硬中斷,軟中斷,接著通過核心執行緒ksoftirqd經過核心協議棧的處理,最終將資料傳送到核心Socket的接收緩衝區中。
- 資料拷貝階段:當資料到達核心Socket的接收緩衝區中時,此時資料存在於核心空間中,需要將資料拷貝到使用者空間中,才能夠被應用程式讀取。
1、阻塞與非阻塞
阻塞與非阻塞到區別主要發生在第一個階段:資料準備階段。
當應用程式發起系統呼叫read時,執行緒從使用者態轉為核心態,讀取核心Socket的接收緩衝區中的網路資料。
阻塞:
如果這時核心Socket的接收緩衝區沒有資料,那麼執行緒就會一直等待,直到Socket接收緩衝區有資料為止。隨後將資料從核心空間拷貝到使用者空間,系統呼叫read返回。
所以阻塞到特點是在第一階段和第二階段都會等待。
非阻塞:
阻塞和非阻塞主要的區分是在第一階段:資料準備階段。
- 在第一階段,當Socket的接收緩衝區中沒有資料的時候,阻塞模式下應用執行緒會一直等待。非阻塞模式下應用執行緒不會等待,系統呼叫直接返回錯誤標誌EWOULDBLOCK。
- 當Socket的接收緩衝區中有資料的時候,阻塞和非阻塞的表現是一樣的,都會進入第二階段等待資料從核心空間拷貝到使用者空間,然後系統呼叫返回。
- 所以,從上述內容可以看出,非阻塞到特點是第一個階段不會等待,但在第二個階段還是會等待。
2、同步與非同步
同步與非同步主要的區別發生在第二階段:資料拷貝階段。
前面我們提到在資料拷貝階段,主要是將資料從核心空間拷貝到使用者空間。然後應用程式才可以讀取資料。
當核心Socket的接收緩衝區有資料到達時,進入第二階段。
同步:
同步模式在資料準備好後,是由使用者執行緒的核心態來執行第二階段。所以應用程式會在第二階段發生阻塞,直到資料從核心空間拷貝到使用者空間,系統呼叫才會返回。
Linux下的epoll和Mac下的kqueue都屬於同步IO。
非同步:
非同步模式下是由核心來執行第二階段的資料拷貝操作,當核心執行完第二階段,會通知使用者執行緒IO操作已完成,並將資料回撥給使用者執行緒。所以在非同步模式下資料準備階段和資料拷貝階段均是由核心來完成,不會對應用程式操作任何阻塞。
機遇以上特徵,我們可以看到非同步模式需要核心的支援,比較依賴作業系統底層的支援。
在目前流行的作業系統中,只有Windows中的IOCP才真正屬於非同步IO,實現的也非常成熟。但Windwos很少用來做伺服器使用。
而常用來作為伺服器使用的Linux,非同步IO機制實現還不夠成熟,與NIO相比效能提升的也不夠明顯。
但Linux kernel在5.1版本由Facebook的大神Jens Axboe引入了新的非同步IO庫io_uring改善了原來Linux native AIO的一些效能問題。效能相比Epoll以及之前原生的AIO提高了不少,值得關注。