C#中的async/await

async方法只能有三种返回值:void, Task, Task<T>。

async void只能直接调用,与调用方并行执行。

async Task可以直接调用,也可以await调用,直接调用是并行执行,await调用会等待执行完。

async Task<T>与async Task类似,只是通过await方式调用可以获得T类型的返回值。

下面通过代码做了一些实验。

    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()");
        }
    }

 

posted on 2018-09-25 17:18  朱迎春  阅读(2818)  评论(1编辑  收藏  举报