async方法只能有三種返回值:void, Task, Task<T>。異步
async void只能直接調用,與調用方並行執行。async
async Task能夠直接調用,也能夠await調用,直接調用是並行執行,await調用會等待執行完。spa
async Task<T>與async Task相似,只是經過await方式調用能夠得到T類型的返回值。線程
下面經過代碼作了一些實驗。code
class Program { static void Main(string[] args) { Console.WriteLine(DateTime.Now.ToString() + " : " + "程序啓動"); Test8(); Console.WriteLine(DateTime.Now.ToString() + " : " + "程序結束"); for (int i = 0; i < 10; i++) { Console.WriteLine(DateTime.Now.ToString() + " : Ticks"); Thread.Sleep(1000); } Console.ReadLine(); } private static void TaskFunc(int n) { Console.WriteLine(DateTime.Now.ToString() + " : " + "Begin Call TaskFunc(" + n + ")"); Thread.Sleep(2000); Console.WriteLine(DateTime.Now.ToString() + " : " + "End Call TaskFunc(" + n + ")"); } /*********************************************************** 2018/9/25 10:51:34 : 程序啓動 2018/9/25 10:51:34 : Begin Call TaskFunc(1) 2018/9/25 10:51:36 : End Call TaskFunc(1) 2018/9/25 10:51:36 : Begin Call TaskFunc(2) 2018/9/25 10:51:38 : End Call TaskFunc(2) :同步調用,兩個任務依次執行,總耗時4秒 2018/9/25 10:51:38 : 程序結束 ***********************************************************/ private static void Test1() { TaskFunc(1); TaskFunc(2); } /*********************************************************** 2018/9/25 11:12:13 : 程序啓動 2018/9/25 11:12:13 : Begin Call TaskFunc(1) 2018/9/25 11:12:13 : Begin Call TaskFunc(2) 2018/9/25 11:12:15 : End Call TaskFunc(1) 2018/9/25 11:12:15 : End Call TaskFunc(2) 2018/9/25 11:12:15 : 程序結束 :主線程阻塞直到所有任務執行完畢 ***********************************************************/ // 並行運行的只有兩個TaskFunc,主線程是阻塞的 private static void Test2() { int[] a = new int[2] { 1, 2 }; Parallel.ForEach(a, n => { TaskFunc(n); }); } /*********************************************************** 2018/9/25 11:03:54 : 程序啓動 2018/9/25 11:03:54 : Begin Call TaskFunc(1) 2018/9/25 11:03:54 : Begin Call TaskFunc(2) 2018/9/25 11:03:56 : End Call TaskFunc(1) 2018/9/25 11:03:56 : End Call TaskFunc(2) :兩個任務同時開始同時結束,總耗時2秒 2018/9/25 11:03:56 : 程序結束 :Task.WaitAll阻塞了主線程 ***********************************************************/ // 並行運行的只有兩個TaskFunc,主線程是阻塞的,與Test2相同 // 去掉Task.WaitAll,能夠實現主線程、兩個TaskFunc並行,但沒法在兩個TaskFunc完成後作些事情 private static void Test3() { Task t1 = Task.Run(() => { TaskFunc(1); }); Task t2 = Task.Run(() => { TaskFunc(2); }); Task.WaitAll(t1, t2); } /*********************************************************** 2018/9/25 11:01:32 : 程序啓動 2018/9/25 11:01:32 : Begin Call TaskFunc(1) 2018/9/25 11:01:32 : Begin Call TaskFunc(2) 2018/9/25 11:01:34 : End Call TaskFunc(1) 2018/9/25 11:01:34 : End Call TaskFunc(2) :兩個任務同時開始同時結束,總耗時2秒 2018/9/25 11:01:34 : 程序結束 :EndInvoke阻塞了主線程 ***********************************************************/ // 並行運行的只有兩個TaskFunc,主線程是阻塞的,與Test2,Test3相同 private static void Test4() { Action a1 = () => { TaskFunc(1); }; Action a2 = () => { TaskFunc(2); }; IAsyncResult iar1 = a1.BeginInvoke(null, null); IAsyncResult iar2 = a2.BeginInvoke(null, null); a1.EndInvoke(iar1); a2.EndInvoke(iar2); } /*********************************************************** 2018/9/25 17:05:08 : 程序啓動 2018/9/25 17:05:08 : 程序結束 :放在callback中的EndInvoke不會阻塞主線程 2018/9/25 17:05:08 : Ticks 2018/9/25 17:05:08 : Begin Call TaskFunc(1) 2018/9/25 17:05:08 : Begin Call TaskFunc(2) 2018/9/25 17:05:09 : Ticks 2018/9/25 17:05:10 : Ticks 2018/9/25 17:05:10 : End Call TaskFunc(1) 2018/9/25 17:05:10 : End Call TaskFunc(2) :兩個任務同時開始同時結束,總耗時2秒 ***********************************************************/ // 主線程、兩個TaskFunc並行運行 // 能夠在AsyncCallback種添加TaskFunc結束後的代碼,而且不會阻塞主線程 private static void Test5() { Action a1 = () => { TaskFunc(1); }; Action a2 = () => { TaskFunc(2); }; a1.BeginInvoke(new AsyncCallback(iar => { a1.EndInvoke(iar); }), null); a2.BeginInvoke(new AsyncCallback(iar => { a2.EndInvoke(iar); }), null); } /*********************************************************** 2018/9/25 17:06:48 : 程序啓動 2018/9/25 17:06:48 : 程序結束 :await沒有阻塞主線程 2018/9/25 17:06:48 : Ticks 2018/9/25 17:06:48 : Begin Call TaskFunc(2) 2018/9/25 17:06:48 : Begin Call TaskFunc(1) 2018/9/25 17:06:49 : Ticks 2018/9/25 17:06:50 : Ticks 2018/9/25 17:06:50 : End Call TaskFunc(1) 2018/9/25 17:06:50 : End Call TaskFunc(2) 2018/9/25 17:06:50 : End Call Test6() :阻塞異步調用,等待任務完成 ***********************************************************/ // 主線程、兩個TaskFunc並行運行 // await沒有阻塞主線程,達到了Test5類似的功能,代碼更簡潔 private static async void Test6() { Task t1 = Task.Run(() => { TaskFunc(1); }); Task t2 = Task.Run(() => { TaskFunc(2); }); await Task.WhenAll(t1, t2); Console.WriteLine(DateTime.Now.ToString() + " : " + "End Call Test6()"); } /*********************************************************** 2018/9/25 17:10:20 : 程序啓動 2018/9/25 17:10:21 : Begin Call TaskFunc(1) 2018/9/25 17:10:22 : Begin Call TaskFunc(2) 2018/9/25 17:10:23 : 程序結束 2018/9/25 17:10:23 : Ticks 2018/9/25 17:10:23 : End Call TaskFunc(1) 2018/9/25 17:10:24 : End Call TaskFunc(2) 2018/9/25 17:10:24 : End Call Test6() 2018/9/25 17:10:24 : Ticks 2018/9/25 17:10:25 : Ticks 2018/9/25 17:10:26 : Ticks 2018/9/25 17:10:27 : End Call Test6() ***********************************************************/ // await以前的Sleep阻塞了主線程,await以後的Sleep沒有阻塞主線程 private static async void Test7() { Thread.Sleep(1000); Task t1 = Task.Run(() => { TaskFunc(1); }); Thread.Sleep(1000); Task t2 = Task.Run(() => { TaskFunc(2); }); Thread.Sleep(1000); await Task.WhenAll(t1, t2); Console.WriteLine(DateTime.Now.ToString() + " : " + "End Call Test6()"); Thread.Sleep(3000); Console.WriteLine(DateTime.Now.ToString() + " : " + "End Call Test6()"); } /*********************************************************** 2018/9/25 17:14:01 : 程序啓動 2018/9/25 17:14:04 : Begin Call TaskFunc(1) 2018/9/25 17:14:06 : End Call TaskFunc(1) 2018/9/25 17:14:07 : Begin Call TaskFunc(2) 2018/9/25 17:14:09 : End Call TaskFunc(2) 2018/9/25 17:14:10 : End Call Test6() 2018/9/25 17:14:13 : End Call Test6() 2018/9/25 17:14:13 : 程序結束 ***********************************************************/ // 在await調用的時候,兩個Task都已經結束了,await以後的Sleep也阻塞了主線程 private static async void Test8() { Thread.Sleep(3000); Task t1 = Task.Run(() => { TaskFunc(1); }); Thread.Sleep(3000); Task t2 = Task.Run(() => { TaskFunc(2); }); Thread.Sleep(3000); await Task.WhenAll(t1, t2); Console.WriteLine(DateTime.Now.ToString() + " : " + "End Call Test6()"); Thread.Sleep(3000); Console.WriteLine(DateTime.Now.ToString() + " : " + "End Call Test6()"); } }