HTML5技术

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

字号+ 作者:H5之家 来源:博客园 2015-12-05 11:22 我要评论( )

又到了周末的code review环节,这次code review发现了一个对async/await的理解问题。让我们直奔主题: var foodsSearch = new FoodSearchService().SearchAsync();var fruitsSearch = new FruitSearchService().SearchAsync();var foods = await foodsSearch

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

var foodsSearch = new FoodSearchService().SearchAsync(); var fruitsSearch = new FruitSearchService().SearchAsync(); 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().SearchAsync(); var fruitsSearch = new FruitSearchService().SearchAsync(); var foods = foodsSearch.Result; foods.ForEach(f => Console.WriteLine("food:{0}", f.Name)); Console.WriteLine("done");

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

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

为了说明这个结论,我们用下面的代码模拟await,我没有研究过await的实现,但是下面的代码跟await具有相同的行为:

var foodsSearch = new FoodSearchService().SearchAsync(); var fruitsSearch = new FruitSearchService().SearchAsync(); 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)); } }

从上面模拟的代码中我们可以得出两个结论:

1、没有任何阻塞主线程的代码。

2、尽量推迟await的调用,能在步骤2使用await就不要在步骤1使用。因为一旦使用了await,后面所有的代码都变成了await所调用对象的回调,无法跟之前的异步代码并行。即便你在步骤1就使用了await,只能说FoodSearchService和FruitSearchService两者不能并行,但是任然不会阻塞主线程——在主线程上永远没有等待这一说。

我们再看张图来解释一下这期间发生的事情:

设想这样的代码放在一个GUI中Button的click事件中,由于await不会阻塞主线程,界面再不会有假死的情况发生。

this.BackColor = Color.Aquamarine; this.btnAsyncAwait.BackColor = Color.Blue; var operationA = new LongTimeOperationA().GetValueAsync(); var operationB = new LongTimeOperationB().GetValueAsync(); var valueA =await operationA; Text = valueA;

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

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

async/await的使用并不会提升访问数据库的效率,该花多长时间还得花多长时间。

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

this.BackColor = Color.Beige; this.btnTaskResult.BackColor = Color.BlueViolet; var operationA=new LongTimeOperationA().GetValueAsync(); var operationB=new LongTimeOperationB().GetValueAsync(); var valueA = operationA.Result; Text = valueA;

代码下载:download

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • HTML5中的新事件 - zxyGo

    HTML5中的新事件 - zxyGo

    2017-03-10 14:00

  • canvas中的非零环绕原则 - 一混五六年

    canvas中的非零环绕原则 - 一混五六年

    2017-02-22 10:00

  • .NET 十五岁,谈谈我眼中的.NET - 张善友

    .NET 十五岁,谈谈我眼中的.NET - 张善友

    2017-02-16 15:00

  • 北漂的程序猿何去何从 - 梦中的梦中

    北漂的程序猿何去何从 - 梦中的梦中

    2017-02-14 16:00

网友点评
-