io操作中常見的幾個概念
1. 概述
web應用中,io這塊是一個重點,不同的策略對系統的性能影響很大.
對于io操作來說,用戶線程發起io請求,內核負責完成此請求,并反饋結果,這兩個角色之間需要進行協調:
1. 系統掛起用戶線程,操作完成之后,系統返回結果,喚醒用戶線程
2. 系統返回狀態碼,用戶線程輪詢結果,直到操作完成.
3. 用戶線程發起請求時附帶回調信息,內核接受請求后返回,用戶線程執行別的邏輯;系統會在操作完成之后回調,有的系統自動創建新用戶線程完成io處理,有的系統會利用已有的用戶線程執行處理邏輯
4. 用戶系統注冊一個大的信號處理線程,用戶線程發起請求后直接返回,系統在操作完成之后發送信號,信號處理線程接手處理.
可以看出,有的方式會造成線程掛起等待,有的會造成線程空轉;一個線程好不容易等到系統分配了時間片,卻又無奈的交出自己的時間片,浪費系統資源,我們的目標就是盡量少的線程,盡量少浪費線程的時間片,盡量少的線程切換,要做到這點,還是先來說說io中較常見的同步、異步、阻塞和非阻塞這幾個概念.
2. 同步
我理解的io同步是指線程做io請求時需要等待內核將數據準備好,浪費了自己的cpu時間片.比如read,如果數據沒準備好則線程直接掛起,浪費了一次線程調度;如果數據準備好了,需要將數據從內核空間拷貝到用戶空間,可能分給自己1ms,結果等待拷貝數據花了了0.5ms,,實際只花費了0.5ms在業務上.
也有人是從當前線程是否需要等待處理結果來考量,當前線程需要等待,那就是同步,這個和我的觀點實際沒差別,到了異步這兒就不太一樣,我們下面說.
3. 異步
與同步模式相反,異步模式下用戶線程只需要注冊相關信息,操作系統在操作完成后,將數據從內核空間拷貝到用戶空間,然后根據注冊信息通知用戶進程處理io結果.整個流程中無需用戶線程干預,用戶線程可以充分利用分配給自己的時間.
有的io調用返回的是狀態碼,用戶線程再根據狀態碼做相應的處理,但實際去做io操作時還是要主動的發起系統調用去獲取數據,這是同步模型;還有的io操作是通過信號驅動,內核在操作完成后發送信號通知用戶進程處理,用戶進程捕獲到信號后再發起系統調用去讀取數據,實際上還是同步模式.
回到前面的問題,當前線程不等待io的操作結果這是否可以認為是異步?
我是這樣想的,io數據從內核空間拷貝到用戶空間這一步所花費的時間,不花在這個用戶線程就花在別的用戶線程,,總是消耗了用戶線程的cpu時間片,除非由內核來驅動用戶線程.
4. 阻塞
阻塞是指進行io操作時是否引起線程掛起,掛起了就是阻塞模式.很多時候會把同步和阻塞混淆,主要是因為同步一般都是由阻塞實現的.仔細想想,非阻塞也可以是同步,創建socket時如果指定BLOCK為false,那所有的操作都變成非阻塞,此時可能還是同步模式.
阻塞模式既有有點又有缺點,因為會阻塞,在請求不活躍時會節約cpu;因為會阻塞,也就造成了線程切換,也就浪費了cpu.
5. 非阻塞
沒啥好說的,線程一路暢通無阻,看起來挺好,可如果忙著做狀態檢測,那就極大的浪費了cpu資源.
5 四種理論模型
同步異步,阻塞非阻塞,交叉組合,共有四種模型
5.1 同步阻塞
最經典的使用方式,最簡單的,最喜歡的....
io操作會引起線程阻塞,只有系統準備好了時才會有返回,可以說不會浪費任何cpu資源.一般會有少量的線程接入請求,再來一個線程池處理接入的請求,簡單有效.如果你的系統處理的連接不多,或者大部分不活躍,不用猶豫就它了.
在請求頻繁時,同步阻塞會放大線程調度的成本,如果總得連接數超過線程池大小還會造成請求排隊,此時還是盡早調整策略.
5.2 同步非阻塞
建立socket時,可以指定no block,此時所有的操作都會立刻返回,線程再根據返回值做相應的處理,這是一種輪詢的方案,相比于同步阻塞,會多出若干次的系統調用,很不合算.
另外還有一種多路復用的io模式,線程先向內核注冊若干個感興趣的事件,然后一直等待,在某個或若干個事件符合條件后,內核將其打包返回,線程接到返回值,再去處理事件.
相比于直接在read/write上block住,同步阻塞多了一個獲取事件的調用,因此相比于同步阻塞會有額外的系統開銷;不過,因為一個線程可以同時監聽多個連接,也就能一次處理若干個連接,在連接數較多時可以節約線程調度的成本,優勢明顯.
5.3 異步阻塞
這個沒啥說的,略
5.4 異步非阻塞
用戶線程先發起io請求,內核立刻返回,于是用戶線程就可以做其它的事.在數據準備好之后,內核會將數據拷貝到用戶空間,再給用戶線程發送操作完成的通知.這個模型下,可以每個事件一個線程,也可以每個連接一個線程,相比于其他模式,能夠最大化的節省線程數;另外,由于用戶線程不需要去主動檢查,每個用戶線程都能用滿自己的時間片,整個系統的性能值得期待.
理論說得這么好可別輕易動心,能用夠用省力氣才是王道,一般的用個同步阻塞就夠了.真要用異步io,最好測測,以前的linux的異步io實現的不是太好,不知道現在啥狀況了.
6 java中的模型
jdk一開始僅支持bio模式,也就是同步阻塞模式,在1.4中提供了nio,支持多路復用,1.7中又引入了aio,支持異步io.
推薦文章
2025-01-18
2024-11-28
2024-11-09
2024-10-25
2024-06-25
2024-01-04
2023-11-06
2023-10-30
2023-10-13
2023-10-10
穩定
產品高可用性高并發貼心
項目群及時溝通專業
產品經理1v1支持快速
MVP模式小步快跑承諾
我們選擇聲譽堅持
10年專注高端品質開發