寫了段小代碼,給同事示範一下這2個文法糖的代碼執行順序:
class Program { static void Main() { Msg("Begin"); DisplayValue(); Msg("End"); Console.Read(); } #region async 測試 public static async Task<double> GetValueAsync(double num1, double num2) { Msg("Into GetValueAsync"); var ret = await Task.Run(() => { Msg("Into GetValueAsync Task"); for (int i = 0; i < 1000000; i++) num1 = num1 / num2; Msg("out GetValueAsync Task"); return num1; }); Msg("out GetValueAsync"); return ret; } public static async void DisplayValue() { Msg("Into DisplayValue"); var result = GetValueAsync(1234.5, 1.01); Msg("Middle DisplayValue"); Msg("Value is : " + await result); Msg("Out DisplayValue"); } #endregion private static int idx; static void Msg(string msg) { Interlocked.Increment(ref idx); var id = Thread.CurrentThread.ManagedThreadId.ToString(); Console.WriteLine(idx.ToString() + ". 線程:" + id + " " + msg); Thread.Sleep(100); // 避免cpu不定,導致順序打亂 } }
代碼執行結果:
1. 線程:1 Begin2. 線程:1 Into DisplayValue3. 線程:1 Into GetValueAsync4. 線程:1 Middle DisplayValue5. 線程:3 Into GetValueAsync Task6. 線程:1 End7. 線程:3 out GetValueAsync Task8. 線程:3 out GetValueAsync9. 線程:3 Value is : 2.47032822920623E-32210. 線程:3 Out DisplayValue
把GetValueAsync方法的async和await 移除
public static Task<double> GetValueAsync(double num1, double num2){ Msg("Into GetValueAsync"); var ret = Task.Run(() => { Msg("Into GetValueAsync Task"); for (int i = 0; i < 1000000; i++) num1 = num1 / num2; Msg("out GetValueAsync Task"); return num1; }); Msg("out GetValueAsync"); return ret;}
執行順序就變了,結果如下:
1. 線程:1 Begin2. 線程:1 Into DisplayValue3. 線程:1 Into GetValueAsync4. 線程:1 out GetValueAsync5. 線程:3 Into GetValueAsync Task6. 線程:1 Middle DisplayValue7. 線程:1 End8. 線程:3 out GetValueAsync Task9. 線程:3 Value is : 2.47032822920623E-32210. 線程:3 Out DisplayValue
你看明白了嗎。如果不明白,把上面的測試代碼複製到你的項目裡,改一改,運行一下吧,
簡單總結一下:
- await指令調起線程執行非同步方法呼叫和方法內後面的代碼
- await指令會阻塞當前方法後面的代碼,但是不會阻塞外部調用
- await必須搭配async使用,而async不一定需要有await