同步I/O模型要求用戶代碼自行執(zhí)行I/O操作(將數(shù)據(jù)從內核緩沖區(qū)讀入用戶緩沖區(qū),或將數(shù)據(jù)從用戶緩沖區(qū)寫入內核緩沖區(qū)),而異步I/O則由內核來執(zhí)行I/O操作。
同步I/O向應用程序通知的是I/O就緒事件,而異步I/O向應用程序通知的是I/O完成時間。
1. Reactor模式
工作流程:
- 主線程網epoll內核事件表中注冊socket上的讀就緒時間
- 主線程調用epoll_wait等待socket上有數(shù)據(jù)可讀
- 當socket上有數(shù)據(jù)可讀時,epoll_wait通知主線程。主線程則將socket可讀事件放入請求隊列
- 睡眠在請求隊列的某個工作線程被喚醒,它從socket讀取數(shù)據(jù),并處理客戶請求,然后往epoll內核事件表中注冊該socket上的寫就緒時間
- 主線程調用epoll_wait等待socket可寫
- 當socket可寫時,epoll_wait通知主線程。主線程將socket可寫事件放入請求隊列
- 睡眠在請求隊列上的某個工作線程被喚醒,它往socket上寫入服務器處理客戶請求的結果
2. Proactor模式
工作流程:
- 主線程調用aio_read函數(shù)向內核注冊socket上的讀完成事件,并告訴內核用戶讀緩沖區(qū)的位置,以及讀操作完成時如何通知應用程序(信號為例)
- 主線程繼續(xù)處理其他邏輯
- 當socket上的數(shù)據(jù)被讀入用戶緩沖區(qū)后,內核將向應用程序發(fā)送一個信號,以通知應用程序數(shù)據(jù)已經可用
- 應用程序預先定義好的信號處理程序選擇一個工作線程來處理客戶請求。工作線程處理完客戶請求之后,調用aio_write函數(shù)向內核注冊socket上的寫完成時間,并告訴內核用戶寫緩沖區(qū)的位置,以及寫操作完成時如何通知應用程序(信號)
- 主線程繼續(xù)處理其他邏輯
- 當用戶緩沖區(qū)的數(shù)據(jù)被寫入socket之后,內核將向應用程序發(fā)送一個信號,以通知應用程序數(shù)據(jù)已經發(fā)送完畢
- 應用程序預先定義好的信號處理函數(shù)選擇一個工作線程來做善后處理
3. 模擬Proactor模式
使用同步I/O方法可以模擬Proactor模式:主線程執(zhí)行數(shù)據(jù)讀寫操作,讀寫完成之后,主線程向工作線程通知這一“完成事件”,那么從工作線程的角度看,它們就直接獲得了數(shù)據(jù)讀寫的結果,只需要對讀寫的結果進行邏輯處理。
4. 半同步/半異步模式
這里的同步異步不是I/O模型的,而是并發(fā)模式的:
同步指的是程序完全按照代碼序列的順序執(zhí)行,異步指的是程序的執(zhí)行需要由系統(tǒng)事件來驅動、
半同步/半異步模式中,同步線程用于處理客戶邏輯,異步線程用于處理I/O事件(主線程,負責分發(fā)任務)。
結合考慮這兩種事件處理模式和幾種I/O模型,存在多種變體:
半同步半反應堆模式

半同步半反應堆模式.jpg
異步線程:主線程
事件處理模式:Reactor,請求隊列的任務時就緒的連接socket,工作線程自己從socket上讀取客戶請求和寫入應答
缺點:
- 主線程和工作線程共享請求隊列,需要加鎖保護,耗費時間
- 每個工作線程同一時間只能處理一個客戶請求,容易堆積任務
半同步/半異步模式

半同步半異步模式.jpg
每個工作線程都能同時處理多個客戶連接
主線程只管理監(jiān)聽socket,連接socket由工作線程管理,主線程通過管道向工作線程分發(fā)任務
每個線程(主線程和工作線程)都維持自己的時間循環(huán),各自獨立地監(jiān)聽不同的時間。
領導者/追隨者模式
多個工作線程輪流獲得事件源集合,輪流監(jiān)聽、分發(fā)并處理事件。
提高性能
- 資源池:避免頻繁分配和銷毀資源開銷
- 數(shù)據(jù)復制:避免不必要的文件復制,共享內存,傳遞指針
- 上下文切換和鎖:避免頻繁切換,減小鎖的粒度,讀寫鎖等。