Boost.Asio 有兩種支持多線程的方式,第一種方式比較簡單:在多線程的場景下,每個線程都持有一個io_service
,並且每個線程都調用各自的io_service
的run()
方法。
另一種支持多線程的方式:全局只分配一個io_service
,並且讓這個io_service
在多個線程之間共享,每個線程都調用全局的io_service
的run()
方法。
一、每個線程一個 I/O Service
在多線程的場景下,每個線程都持有一個io_service
(通常的做法是,讓線程數和 CPU 核心數保持一致)。
- 在多核的機器上,這種方案可以充分利用多個 CPU 核心。
- 某個 socket 描述符並不會在多個線程之間共享,所以不需要引入同步機制。
- 在 event handler 中不能執行阻塞的操作,否則將會阻塞掉
io_service
所在的線程。
二、一個 I/O Service 與多個線程
另一種方案則是先分配一個全局io_service
,然後開啓多個線程,每個線程都調用這個io_service
的run()
方法。這樣,當某個異步事件完成時,io_service
就會將相應的 event handler 交給任意一個線程去執行。
然而這種方案在實際使用中,需要注意一些問題:
- 在 event handler 中允許執行阻塞的操作 (例如數據庫查詢操作)。
- 線程數可以大於 CPU 核心數,譬如說,如果需要在 event handler 中執行阻塞的操作,爲了提高程序的響應速度,這時就需要提高線程的數目。
- 由於多個線程同時運行事件循環(event loop),所以會導致一個問題:即一個 socket 描述符可能會在多個線程之間共享,容易出現競態條件 (race condition)。譬如說,如果某個 socket 的可讀事件很快發生了兩次,那麼就會出現兩個線程同時讀同一個 socket 的問題 (可以使用
strand
解決這個問題)。