Boost Asio要點概述(一)
【注】本文不是boost asio的完整應用講述,而是僅對其中要點的講解,主要參考了Boost Asio 1.68的官方文件(https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/overview.html),程式碼的測試環境為ubuntu 18.04,asio的編譯及安裝不在本文的範圍之內。
一、基本工作流程
下圖來自boost asio的官網,顯示了Asio的基本工作流程。
圖1是同步工作方式,你的程式呼叫I/O介面(通過I/O object,步驟1),其實是呼叫了io_context的介面(步驟2),io_context呼叫了作業系統I/O介面(步驟3),等待,作業系統返回(步驟5),io_context返回(步驟6),I/O object返回給你的程式(步驟7)。如果不用Asio的話,你的程式直接呼叫作業系統介面,等待,然後作業系統返回(步驟1,4)。
圖2是非同步工作方式(兩個階段),第一階段,你的程式呼叫I/O介面(通過I/O object,步驟1),同時提供一個完成控制代碼(函式),其實是呼叫了io_context的介面(步驟2),io_context告訴作業系統有非同步I/O(步驟3),作業系統開始工作並直接返回。第二階段,作業系統在核心態完成I/O操作後,將結果拷貝出來,然後通知io_context(步驟4),同時你的程式也可以抽空做點別的事情(不能太多,否則阻塞了完成訊息的處理),然後呼叫io_context.run(),將控制權交回io_context(步驟5,否則你的完成控制代碼函式得不到呼叫)。io_context呼叫完成控制代碼函式。步驟4和步驟5其實不分先後,同時發生。
無論同步或非同步方式,io_context都處於中心地位,它負責與作業系統發生關係,同步時,它封裝了作業系統的I/O呼叫,非同步時,它通知作業系統要進行I/O,準備好非同步操作的相關引數,同時,它需要維護一個佇列(同時進行的非同步I/O操作不止一個),保證作業系統的操作完成後,找到對應的完成控制代碼函式,然後呼叫它。
二、Proactor模式
Boost.Asio用的是Proactor模式。要理解Poactor,先要理解同步/非同步和阻塞/非阻塞概念。網上已有多篇文章論述。其實,各人在IO處理時,對同步/非同步,阻塞/非阻塞的理解並不完成一致,下面兩個圖分別來自UNIX Network Programming和微軟的官方網站,它們就有點區別,微軟網文的處理比較簡潔,似乎同步就意味著阻塞,非同步就意味著非阻塞。UNIX書中阻塞/非阻塞是指使用者呼叫系統IO函式時是否立即返回,同步/非同步是指系統將IO操作的結果告訴使用者的方式。
上圖來自UNIX Network Programming
上圖來自微軟的網文“Synchronous and Asynchronous I/O”
Proactor/Reactor模式也是否相像,二者都靠訊息來驅動,都有回撥函式,Proactor中,系統為你做了更多,告訴你結果,Reactor中,只是告訴你有事情發生了,可以做點什麼了。
需要說明的是,並不是所有場合非阻塞非同步方式的效能都最高,其實活還是那麼多,系統幫你多做了些而已。如果只有少數幾個連線,多執行緒+同步方式也許更適合。