C#中,.Net Framework4.5+的Async/Await使用(让你的异步更加异步)

先上代码

public class TestAsyncAwaitService
    {
        public static async void Run()
        {
            var threadId = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("主线程{0}:Begin ShowTimeAsync", threadId);
            Console.WriteLine("主线程{0}:Begin ShowNowAsync", threadId);

            var msg = ShowTimeAsync();
            var aaa = ShowNowAsync();

            //不使用异步执行返回值,不会被阻塞
            //Console.WriteLine("msg = " + msg);

            //如果要使用到异步执行的返回值,主线程就会阻塞,直到获取到异步执行结果
            //Console.WriteLine("msg = " + msg.Result);

            //无返回值的无法等待
            Console.WriteLine("aaa = " + aaa);

            //还有一种可以让主线程阻塞的办法,就是await已经await的方法,
            //这个听起来很绕哈,大家可以理解为负负得正,
            //一个await是异步,再一个await就是同步了,此时就会导致主线程阻塞了
            var msg1 = await ShowTimeAsync();
            await ShowNowAsync();

            Console.WriteLine("主线程{0}:End ShowTimeAsync", threadId);
            Console.WriteLine("主线程{0}:End ShowNowAsync", threadId);
        }

        public static async Task<string> ShowTimeAsync()
        {
            return await Task.Run(() =>
            {
                var threadId = Thread.CurrentThread.ManagedThreadId;
                Console.WriteLine("线程{0}开始数数...", threadId);
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("线程{0}正在数数:{1}", threadId, i + 1);
                    Thread.Sleep(1000);
                }
                return string.Format("线程{0}数数完毕!", threadId);
            });
        }

        public static async Task ShowNowAsync()
        {
            await Task.Run(() =>
            {
                var threadId = Thread.CurrentThread.ManagedThreadId;
                Console.WriteLine("线程{0}开始ShowNow...", threadId);
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("线程{0}正在ShowNow,i = {1},now = {2}", threadId, i + 1,
                        DateTime.Now.ToString("HH:mm:ss"));
                    Thread.Sleep(1000);
                }
                Console.WriteLine("线程{0}ShowNow完毕...", threadId);
            });
        }

        public static void RunTestForResult()
        {
            var watch = new Stopwatch();
            Console.WriteLine("主线程begin,开始计时");
            watch.Start();
            Console.WriteLine("执行到a,同时开始异步计算c");
            var c = CAsync(100, 88);
            for (int i = 0; i < 7; i++)
            {
                Console.WriteLine("主线程从a执行到b需要7秒钟:{0}", i + 1);
                Thread.Sleep(1000);
            }
            Console.WriteLine("执行b,b需要c的返回值,c的返回值(计算结果)为:{0}", c.Result);
            Console.WriteLine("主线程end,共耗时{0}毫秒", watch.ElapsedMilliseconds);//10030
            watch.Stop();
        }

        public static async void RunTestForDoubleAwait()
        {
            var watch = new Stopwatch();
            Console.WriteLine("主线程begin,开始计时");
            watch.Start();
            Console.WriteLine("执行到a");
            for (int i = 0; i < 7; i++)
            {
                Console.WriteLine("主线程从a执行到b需要7秒钟:{0}", i + 1);
                Thread.Sleep(1000);
            }
            Console.WriteLine("执行b,b需要c的返回值,c的返回值(计算结果)为:{0}", await CAsync(100, 88));
            Console.WriteLine("主线程end,共耗时{0}毫秒", watch.ElapsedMilliseconds);//17034
            watch.Stop();
        }

        public static async Task<int> CAsync(int num, int addNum)
        {
            return await Task.Run(() =>
            {
                var id = Thread.CurrentThread.ManagedThreadId;
                Console.WriteLine("线程{0}开始执行求和操作:{1} + {2}", id, num, addNum);
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("线程{0}在执行c操作:{1}", id, i + 1);
                    Thread.Sleep(1000);
                }
                Console.WriteLine("线程{0}计算完毕", id);
                return num + addNum;
            });
        }

        //public static async void RunNormal()
        //{
        //    var id = Thread.CurrentThread.ManagedThreadId;
        //    Console.WriteLine("进入RunNormal,线程id = " + id);
        //    var sum = await Task.Run(() => Sum(100, 88));
        //    Console.WriteLine("RunNormal结束,线程id = " + id);
        //}

        public static int Sum(int num, int addNum)
        {
            var id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("线程{0}开始执行求和操作:{1} + {2}", id, num, addNum);
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("线程{0}求和操作:{1}", id, i + 1);
                Thread.Sleep(1000);
            }
            Console.WriteLine("线程{0}求和完毕", id);
            return num + addNum;
        }
    }

个人一些理解,有不对的请指正,大神勿喷:
1.async/await方法的返回值可以有三种:void,task,task<T>,但是我推荐大家在使用的时候,只使用后两种,也就是task和task<T>,这样可以方便上端去管控执行顺序。
2.想要异步执行完毕再往下执行的方式有两种:
①:使用result,如我demo中的msg.Result,此时主线程会异步去执行msg,但是执行到msg.Result时,就会等待异步执行完毕才会继续往下执行
②:使用我1中所说的双重await,表示同步
综上所述,我个人认为的在开发中使用①好一些(个人理解),因为①分为两步:执行和等待,②只有一步:执行并等待
举个例子:a异步调用c,c执行完毕需要10秒,主线程从a执行到b需要3秒
按照①的说法使用msg.Result,那就是a调用c,c就开始执行了,这是第一步,a执行到b的时候,c已经执行了3s,此时b需要c的结果,主线程只需要再等7秒就可以,所以从a到c执行完毕,一共是3+7=10s
按照②的说法使用双重await,那就是a正常执行,耗时3秒执行到b,b需要等待c执行完,此时b = await c,c此时才开始执行,所以主线程需要等待10s,所以从a到c执行完毕,一共是3+10=13s
我已经将例子在代码中写出来了,大家可以运行参考,使用msg.Result的方法是RunTestForResult,使用双重await的方法是RunTestForDoubleAwait

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值