程序員修神之路--問世間異步為何物?



菜菜哥,今天天氣挺熱的,我都穿裙子了

說吧,什么事??

苦笑一下..... 老大說把所有的接口都改成異步操作

異步好呀,最少比同步能提高吞吐量

異步是怎么回事呢,能講講不?

來,湊近一點,哥給你解釋一番

◆◆
異步定義
◆◆


關於異步的定義,網上有很多不同的形式,但是歸根結底中心思想是不變的。無論是在http請求調用的層面,還是在cpu內核態和用戶態傳輸數據的層面,異步這個行為針對的是調用方:

一個可以無需等待被調用方的返回值就讓操作繼續進行的方法


在多數程序員的概念中一般是指線程處理的層面:

異步是計算機多線程的異步處理。與同步處理相對,異步處理不用阻塞當前線程來等待處理完成,而是允許后續操作,直至其它線程將處理完成,並回調通知此線程


可以這樣通俗的理解,異步主要解決的問題是不阻塞調用方,用方這里可以是http請求的發起者,也可以是一個線程。


但此處需要明確的是:異步與多線程與並行不是同一個概念。


◆◆
CPU密集型操作
◆◆


我聽有的同學說,異步解決的是IO密集型的操作,菜菜覺得是不准確的。異步同樣可以解決CPU密集型操作,只不過場景有限而已。有一個前提:利用異步解決CPU密集型操作要求當前運行環境支持多線程才行,比如javascript這個語言,本質上它的運行環境是單線程的,所以對於CPU密集型操作,javascript會顯得力不從心。


異步解決CPU密集操作一般情況下發生在同進程中,為什么這么說呢,如果發生在不同機器或者不同進程在很多情況下已經屬於IO密集型的范圍了。這里順便提醒一下:IO操作可不單單是指磁盤的操作,所有有輸入/輸出(Input/Output)操作的都可以泛稱為IO。


舉個栗子吧:

在一個帶有UI的軟件上點擊一個按鈕,UI線程會發生操作行為,假如UI線程在執行過程中有一個計算比較耗時的操作(你可以想象成計算1--999999999的和),UI線程在同步操作的情況下會一直等待計算結果,在計算完畢之后才會繼續執行剩余操作,在等待的這個過程中,呈現給用戶的情況就是UI卡住了,俗稱假死了,帶給用戶的體驗是非常不好的。這種情況下,我們可以新啟動一個線程去執行這個耗時的操作,當執行完畢,利用某種通知機制來通知原來線程,以便原來線程繼續自己的操作。


啟動新線程執行CPU密集型操作利用的其實就是多線程的優勢,如果是單核CPU,其實這種優勢並不明顯


◆◆
IO密集型操作
◆◆


異步的優勢在IO密集型操作中表現的淋漓盡致,無論是讀取一個文件還是發起一個網絡請求,菜菜的建議是盡量使用異步。這里首先普及一個小知識:其實每個外設設備都有自己的處理器,比如磁盤,所以每個外設設備都可以處理自己相應的請求操作。但是處理外設設備信息的速度和cpu的執行速度來比較有着天壤之別。


上圖展示了不同的 IO 操作所占用的 CPU 時鍾周期,在計算機中,CPU 的運算速度最快,以其的運算速度為基准,時鍾周期為1。其次是一級緩存、二級緩存和內存,硬盤和網絡最慢,它們所花費的時鍾周期和內存所花費的時鍾周期差距在五位數以上,更不用提跟 CPU 和一級緩存、二級緩存的差距了。


由於速度的差距,所以幾乎所有的IO操作都推薦使用異步。比如當讀取磁盤一個文件的時候,同步狀態下當前線程在等待讀取的結果,這個線程閑置的時間幾乎可以用蛋疼來形容。所以現代的幾乎所有的知名第三方的操作都是異步操作,尤其以Redis,Nodejs 為代表的單線程運行環境令人刮目相看。


現在是微服務盛行的時代,UI往往一個簡單的按鈕操作,其實在后台程序可能調用了幾個甚至更多的微服務接口(關於微服務這里不展開),如果程序是同步操作的話,那響應時間是這些服務接口響應時間的和,但是如果采用的是異步操作,調用方可以在瞬間把調用服務接口的操作發送出去,線程可以繼續執行下邊代碼或者等待所有的服務接口返回值也可以。最差的情況下,接口的響應時間為最慢的那個服務接口響應時間,這有點類似於木桶效應。


◆◆
異步的回調
◆◆


通過以上介紹,我們一定要記住一個知識點:異步需要回調機制。異步操作之所以能在執行結果完成之后繼續執行下面程序完全歸功於回調,這也是所有異步場景的核心所在,前到js的異步回調,后到cpu內核空間copy數據到用戶空間完成通知 等等異步場景,回調無處不在。說道回調大部分語言都是注冊一個回調函數,比如js會把回調的方法注冊到執行的隊列,c#會把回調注冊到IOCP。這里延伸一下,在很多系統里,很多IO網絡模型其實是屬於同步范疇的,比如多路復用技術,真正異步非阻塞的推薦windows下的IOCP。


現在很多現代語言都支持更優秀的回調方式,比如js和c# 現在都支持async 和await方式來進行異步操作。


據說windows下的IOCP才是真正的異步非阻塞模型,求留言區驗證!


◆◆
異步的特點
◆◆


優勢 

1

異步操作無須額外的線程負擔,使用回調的方式進行后續處理,在設計良好的情況下,處理函數可以不必使用共享變量(即使無法完全不用,最起碼可以減少 共享變量的數量),減少了死鎖的可能。

2

線程數量的減少,減少了線程上下文在cpu切換的開銷。

3

微服務環境(調用多個服務接口的情況下)加快了上層接口的響應時間,意味着增加了上層接口的吞吐量

劣勢  

1
異步操作傳統的做法都是通過回調函數來實現,與同步的思維有些差異,而且難以調試
2
如果當前環境有操作順序的要求,異步操作為了保證執行的順序需要做額外的工作
3
由於多數情況下異步的回調過程中的執行線程並非原來的線程,所以在捕獲異常,上下文傳遞等方面需要做特殊處理,特別是不同線程共享代碼或共享數據時容易出問題。
寫在最后
1

在並發量較小的情況下,阻塞式 IO和異步IO的差距可能不是那么明顯,但隨着並發量的增加,異步IO的優勢將會越來越大,吞吐率和性能上的差距也會越來越明顯。

2

在壓力比較小的情況下,一般異步請求的響應時間大於同步請求的響應時間,因為異步的回調也是需要時間的

3

在大並發的情況下,采用異步調用的程序所用線程數要遠遠小於同步調用程序所用的線程數,cpu使用率也一樣(因為避免了太多線程上下文切換的成本)


為了系統性能,不要讓任何設備停下來休息


互聯網之路,菜菜與君一同成長

長按識別二維碼關注

你點的每個推薦,我都認真當成了喜歡  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM