如何理解網絡編程中的阻塞、非阻塞I/O和同步、異步I/O

本文章只單純討論網絡編程中的阻塞、非阻塞 I/O和同步、異步I/O,並不是廣義上定義的對比。因爲這兩種說法在某些方面領域其實意思很接近,甚至可以混用,很難總結出一套說法適用於所有情況。但在用的較多的網絡編程方面,這兩種說法的區別還是很明確的。

我們只要把握住核心的兩點就可以很容易區分出到底屬於哪種I/O操作:

以網絡編程中的recv數據過程爲例,該過程可以簡單理解爲將內核空間收到的網絡數據拷貝到用戶空間。

1. 是用戶進程負責將內核空間數據拷貝到用戶空間,還是內核進程負責這個拷貝過程。

  • 如果是用戶進程負責拷貝,則是同步I/O;
  • 如果是內核進程負責拷貝,則是異步I/O;

2. 如果內核空間的數據還沒有準備好,那麼recv是等待數據準備好然後拷貝;還是立刻返回錯誤,告訴用戶進程內核數據還沒準備好。(拷貝過程實際是由用戶進程負責)

  • 如果recv一直等待數據準備好,完成拷貝後才返回,則是阻塞I/O;
  • 如果內核數據沒有準備好,recv立刻返回錯誤(如EAGAIN錯誤),則是非阻塞I/O;

可以看到,無論是阻塞recv還是非阻塞recv,它從內核空間向用戶空間拷貝數據的過程其實都是由用戶進程負責的,也就是我們的應用程序進程,所以說無論阻塞還是非阻塞,其實都是同步操作。

非阻塞recv相比非阻塞只是多了一種處理方式:如果數據未準備好,立刻返回錯誤,而這時候內核空間數據並沒有向用戶空間進行拷貝。等到數據準備好,非阻塞recv和阻塞式recv一樣,都需要一段時間將數據從內核空間拷貝到用戶空間,這個過程用戶進程只能負責這一件事,就是拷貝數據。所以說阻塞、非阻塞I/O 都是同步操作。

異步I/O則完全不同,因爲它其實將這個拷貝過程交給了內核進程去做,用戶進程並不參與這個拷貝過程,它只需要等內核進程拷貝完畢給我們發個完成信號或事件就行了。在數據拷貝的這段時間,用戶進程可以進行其他工作。

linux雖然已支持異步I/O,不過當前網絡編程中大多還是採用的 select/poll/epoll + send/recv 的 多路I/O複用+同步I/O 模式,異步I/O暫時用的還很少。不過顯然異步操作是趨勢,也是提高服務器性能的關鍵。linux下的異步I/O還是需要大型工程項目背書才能擴展開來。

以下圖片截取自《UNIX網絡編程 卷一 第三版》

阻塞I/O模型

 

非阻塞式I/O模型

 

異步I/O模型

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章