C#中的async/await

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()");
        }
    }
相關文章
相關標籤/搜索