码迷,mamicode.com
首页 > 其他好文 > 详细

你眼中的async/await是什么样的呢?

时间:2015-12-05 00:28:44      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

又到了周末的code review环节,这次code review发现了一个对async/await的理解问题。让我们直奔主题:

            var foodsSearch = new FoodSearchService().Search();
            var fruitsSearch = new FruitSearchService().Search();

            var foods = await foodsSearch;

            foods.ForEach(f => Console.WriteLine("food:{0}", f.Name));

            Console.WriteLine("done");

这是一段使用async/await的代码,算得上是async/await的最佳使用实践。问题出在大家对这段代码理解各有不同,让我们来看看如何理解这段代码:

技术分享

这个理解真确吗?团队的争论焦点在步骤2上,大家错误的认为await关键字就是等待的意思,为了在第三步拿到结果,线程在步骤2处等待直到FoodSearchService返回结果。如果你也是这样理解的,那么你应该看看下面的代码如何理解?

            var foodsSearch = new FoodSearchService().Search();
            var fruitsSearch = new FruitSearchService().Search();

            var foods = foodsSearch.Result;

            foods.ForEach(f => Console.WriteLine("food:{0}", f.Name));

            Console.WriteLine("done");

刚才错误的理解正好是这段代码的描述。那么第一段使用async/await的代码如何理解?

使用await标记的方法调用不会阻塞主线程,主线程在步骤2不会等待。

为了说明这个结论,接下来我们模拟一个简单的实现,我们假设await语法糖会编译出如下的代码:

            var foodsSearch = new FoodSearchService().Search();
            var fruitsSearch = new FruitSearchService().Search();

            var callback = foodsSearch as ICallBackRegister;
            callback.Register<List<Food>>(foods =>
            {
                foods.ForEach(f => Console.WriteLine("food:{0}", f.Name));
                Console.WriteLine("done");
            }).Await(foodsSearch);

为了方便大家理解,我们写一个简单的ICallBackRegister实现:

    public class CallbackRegister:ICallBackRegister
    {
        Action<object> _action; 
        public ICallBackRegister Register<T>(Action<T> callback)
        {
            _action = o => callback((T) o);
            return this;
        }

        public void Await(Task task)
        {
            task.ContinueWith((result)=>_action(result));
        }
    }

实际上await并不是这样实现的,我也没有研究过await的实现,但是await后面的方法调用我们可以理解为以上的代码片段。在上面的代码片段中,主线程没有任何的阻塞,一口气从开始执行到结尾。设想这样的代码放在一个GUI中Button的click事件中,由于await不会阻塞主线程,界面再不回有假死的情况发生。

            this.BackColor = Color.Aquamarine;
            this.btnAsyncAwait.BackColor = Color.Blue;

            var operationA = new LongTimeOperationA().GetValue();
            var operationB = new LongTimeOperationB().GetValue();

            var valueA =await operationA;
            Text = valueA;

同样的道理,在web mvc编程中,如果controller和EF中全程使用async/await,此时假设用户有一个请求过来,IIS会从线程池中取出一个线程来响应用户请求,由于主线程没有任何阻塞,所以IIS会很快将线程回收到了线程池中。当EF返回数据并且返回ActionResult时,IIS再次从线程池中拿出一个线程来对用户请求做响应。所以

正是由于async/await不会阻塞主线程,我们才说async/await会提高IIS的响应能力。

最后我们给出Task.Result版本的click事件,由于调用Task.Result会阻塞主线程,所以你可以看到界面假死的现象。

            this.BackColor = Color.Beige;
            this.btnTaskResult.BackColor = Color.BlueViolet;

            var operationA=new LongTimeOperationA().GetValue();
            var operationB=new LongTimeOperationB().GetValue();

            var valueA = operationA.Result;
            Text = valueA;

代码下载:download

你眼中的async/await是什么样的呢?

标签:

原文地址:http://www.cnblogs.com/richieyang/p/5020849.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!