引用文地址:https://fastapi.tiangolo.com/async/
前言:fastapi是一個廣泛使用的高效的restful api框架,他的作者在這篇講解框架中使用async的說明詳細舉例解釋了異步編程、並發和並行的區別,堪稱經典,於是手癢總結如下(不敢說翻譯)
async使用指導:
- 如果這個請求比較慢,比如連接數據庫讀取數據、文件IO、rpc調用等一般加上async,我想普通項目里大部分請求都會多多少少跟數據庫打交道,所以加的往往比較多;
- 比較快,穩定的使用def即可,也可以把沒有上面情況調用的都按照這類處理;
- 分不清加不加就不加,放心這不是什么大的問題,我在測試中發現不加效率高一丟丟,畢竟async是要開銷的,特別適合首頁這種重緩存的場景;
異步編程:
Asynchronous Code是給語言層面提供一種方式描述程序在某一點等待慢操作比如慢文件讀寫或者需要其它資源協作,從而讓計算機可以在等待中去執行其它工作。文中作者詳細列舉了相對於cpu和內存操作來說慢的多的慢操作如:
- 網絡通信
- 文件讀寫
- 遠程api調用如rpc調用
- 數據庫操作和查詢
異步是相對同步編程來說的,在執行順序上並沒有改變。實際效果就是同一台機器如果有比較多的慢操作使用異步編程可以提高吞吐率。這里再吐槽一下,大部分語言比如python、csharp、go等的async都是協程實現的,只有java是線程實現的。代價:進程>線程>協程,java不是不能用協程來實現完全是因為歷史包袱,線程相對也不會丟失太多的性能。
並發和漢堡的故事
異步的描述通常稱之為並發,它跟並行不是一回事,雖然他們經常都是描述在同一時間內處理不同的事情。在細節上兩者大不相同,可以下面就是用漢堡的故事來理解:
你帶着心愛的小妹擠進忙碌的快餐店,排隊等着付錢買漢堡。
輪到你的時候,你付錢買了兩個很贊的大漢堡。
付錢
收銀員告訴廚房新的訂單,哪怕廚房還在准備前面的漢堡
收銀員告訴你取餐號碼
然后你和小妹找張桌子談談人生談談理想,因為漢堡太贊需要時間慢慢做
你趁這個時間對小妹一陣猛誇,如何如何的魅力,如何如何的動人
輪到你了后去櫃台取走漢堡
然后就可以和小妹一起慢慢品嘗
設想一下,如果是計算機中這個故事會怎么樣
排隊的時候你可能需要被迫傻等,而不是做點有意義的事比如調情,因為收銀員得一個個收錢
當輪到你的時候你才會忙着看菜單,點單,付錢,確認找回來的錢,就算這樣你還是沒有拿到漢堡,只能去找張桌子等待
直到這個時候你才可以做些有意義的事
因為你有取餐號,所以直到顯示屏上通知你可以取餐都不用擔心你的漢堡被偷了
最后你去櫃台取餐,道謝后算是完成任務並開始任務品嘗美味的漢堡。
並行漢堡
現在設想下如果不是並發,而是並行,那么你跟你的小妹來到漢堡店就不是排一個隊伍了,而是並行比如8個隊伍,沒有收銀員只有廚師。
你前面每個人都在等他們的漢堡,拿到漢堡后才能離開櫃台,廚師只有交出漢堡后才會收下一位的訂單。
終於等到你了,付錢,然后等待廚師去廚房做漢堡
沒有取餐號,因為沒人在你前面,這時你和你的小妹只能干一件事就是確保自己在第一個不讓別人搶走漢堡
等待很久以后才能拿走,這里幾乎沒有時間給你調情,真是個悲傷的故事。
在這個並行場景中你和你的小妹是兩個處理器都等待了很久。
快餐店需要8個處理器,而並發下只需要2個。
當然,這個體驗肯定不好。
漢堡總結
這個場景中有非常多的等待,所以它更適合並發系統。這也是web程序遇到的問題。太多太多的用戶,但是你的服務器要等待不那么快的連接,然后還要等待回應。雖然這里的等待是以毫秒記,但是加起來就很恐怖了。所以這就是為什么Web APIs都用異步。
對於大多數現有的python框架都是在異步特性出現前設計的,所以他們大多以並行的方式實現異步,性能不強。
是不是並發比並行更好?
不,使用場景不同,並發適合web程序,但不是所有。比如科學計算,圖形/音頻處理,機器學習,深度學習等都適合並行計算。並行計算主要解決cpu瓶頸。