天天看點

Task 異步小技巧

原文位址:Task 異步小技巧 - 一事冇誠 - 部落格園 (cnblogs.com)

async Task 文法糖出來後,異步程式設計變得非常簡單,适合需要耗費較長時間的任務。

有些小夥伴使用後可能會非常疑惑,使用異步和同步,在耗時上幾乎沒有差别。

下面我們看一個例子,場景是需要調用多個第三方的WebApi,分别是擷取名稱、年齡、性别,由于網絡環境等原因,api響應時間可能會接近1秒

1 public async Task Test()
 2 {
 3     var sw = new Stopwatch();
 4     sw.Start();
 5 
 6     var userName = await GetUserNameAsync();
 7     var userAge = await GetUserAgeAsync();
 8     var userSex = await GetUserSexAsync();
 9 
10     sw.Stop();
11     var ts = sw.Elapsed;
12     Console.WriteLine($"總共耗時:{ts.TotalMilliseconds}ms");
13 }
14 
15 private async Task<string> GetUserNameAsync()
16 {
17     await Task.Delay(500);
18     return "小明";
19 }
20 
21 private async Task<string> GetUserAgeAsync()
22 {
23     await Task.Delay(800);
24     return "11";
25 }
26 
27 private async Task<string> GetUserSexAsync()
28 {
29     await Task.Delay(900);
30     return "11";
31 }      

運作後發現,這個時間2秒多,這使用者體驗肯定是無法忍受的

Task 異步小技巧

 導緻這樣結果的原因是每次進行異步調用的時候,都在異步函數前加上了 await ,這會導緻該線程阻塞,等待直到結果傳回,每個異步函數都await,時間自然就疊加了,為了解決這個問題,使用一個小技巧,可以将代碼改成下面這樣

1 public async Task Test()
 2 {
 3     var sw = new Stopwatch();
 4     sw.Start();
 5 
 6     var userNameTask =  GetUserNameAsync();
 7     var userAgeTask =  GetUserAgeAsync();
 8     var userSexTask =  GetUserSexAsync();
 9 
10     var userName = await userNameTask;
11     var userAge = await userAgeTask;
12     var userSex = await userSexTask;
13 
14     sw.Stop();
15     var ts = sw.Elapsed;
16     Console.WriteLine($"總共耗時:{ts.TotalMilliseconds}ms");
17 }
18 
19 private async Task<string> GetUserNameAsync()
20 {
21     await Task.Delay(500);
22     return "小明";
23 }
24 
25 private async Task<string> GetUserAgeAsync()
26 {
27     await Task.Delay(800);
28     return "11";
29 }
30 
31 private async Task<string> GetUserSexAsync()
32 {
33     await Task.Delay(900);
34     return "11";
35 }      

這次運作的總耗時,就是3個異步中,耗時最長那個 GetUserSexAsync

Task 異步小技巧

 為什麼會這樣呢,這個小技巧的關鍵是這裡,當執行到異步函數的時候,不加 await,不進行等待,這樣就不會造成阻塞,讓這些任務乖乖在别的線程的執行,當需要用到他們的時候,再去等待傳回值,是以時間上不會進行疊加,哪個最長,總耗時就是哪個

1 var userNameTask =  GetUserNameAsync();
2 var userAgeTask =  GetUserAgeAsync();
3 var userSexTask =  GetUserSexAsync();
4 
5 var userName = await userNameTask;
6 var userAge = await userAgeTask;
7 var userSex = await userSexTask;      

 有不對、不好的地方請大佬們指正,我會改正過來,感謝各位大佬