前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅谈Await

浅谈Await

作者头像
莫问今朝
发布2018-08-31 15:16:35
1.1K0
发布2018-08-31 15:16:35
举报
文章被收录于专栏:博客园博客园

   1.Await为什么不会导致堵塞   

   我们都知道Await关键字是.Net FrameWork4.5引入的特性。await使得我们使用异步更加时特别便捷,并且还不会导致线程堵塞。我们在使用时也就莫名其妙的使用。往往不知道为什么不会导致线程堵塞。在这里,简单的谈论下await的一点原理。

     在c#并行编程这本书中是这么介绍await的:async方法在开始时以同步方式执行,在async方法内部,await关键字对它参数执行一个异步等待,它首先检查操作是否已经完成,如果完成,就继续运行(同步方式),否则,会暂停async方法,并返回.留下一个未完成的task,一段时间后,操作完成,async方法就恢复执行.

    看到这句话应该就差不多能想到await为什么不会导致线程堵塞了,当碰到await时如果没有执行成功就先暂停这个方法的执行,执行方法外以下代码,等await操作完成后再执行这个方法await之后的代码。下面以一个例子形式来演示一下

  在这里创建一个窗体项目,我们都知道窗体主线程堵塞时会导致窗体不能移动,所以能很好的看出效果

添加一个简单的方法.

代码语言:javascript
复制
async Task DemoAsync()
        {
            await Task.Run(() => { });
            Thread.Sleep(3000);
        }

这个方法可以看到只有一个await 一个创建异步,然后线程睡眠3秒钟,

  随后创建一个button按钮并添加一个事件,

代码语言:javascript
复制
 private  void button1_Click(object sender, EventArgs e)
        {
            DemoAsync();
            MessageBox.Show("同步代码");
        }

在这个事件中可以看到只调用了异步方法,调用异步方法时也并没有await,然后弹出一句话.

 运行后会发现在点击button按钮时窗体不能被移动了,然后等待了3秒钟才弹出"同步代码"这句话,看到这里我们再看仔细想下上面的概念,好像明白了什么,下面我们改一下DemoAsync方法

代码语言:javascript
复制
  async Task DemoAsync()
        {
            await Task.Run(() => { Thread.Sleep(3000); });
            Thread.Sleep(3000);
        }

可以看到只在子线程中添加了睡眠3秒的代码,然后我们再次运行就会神奇的发现,此时会先弹出"同步代码"这局话,然后等待3秒后窗体就不能被移动.看到这里我们就应该明白了为什么.

 我们的第一次代码没有在子线程编写任何代码,所以await在执行第一次检查操作时就会立即返回,然后执行Thread.Sleep()代码阻塞主线程.

然而第二次代码在子线程中添加了睡眠3秒,所以在第一次检查操作师会发现并不会立即执行完毕,所以方法内以下代码也就是当前代码中的主线程睡眠3秒会作为await的后续代码(类似回调代码),跳出方法执行方法后面的代码,也就是弹出"同步代码"这句话,直到await等待子线程执行完毕后执行主线程睡眠那句代码,也就是主线程阻塞3秒钟.

 2.ConfigureAwait方法

   在Task里中有ConfigureAwait这么一个方法,这个方法是干什么的呢,我们先看下方法注释是怎么解释这个方法的:" 尝试将延续任务封送回原始上下文,则为 true;否则为 false。"  光看这段代码并看不出什么,然后我们再看这么一段话:"一个async方法是由多个同步执行的程序块组成.每个同步程序块之间由await语句分隔.用await语句等待一个任务完成.当该方法在await处暂停时,就可以捕捉上下文(context).如果当前SynchronizationContext不为空,这个上下文就是当前SynchronizationContext.如果为空,则这个上下文为当前TaskScheduler.该方法会在这个上下文中继续运行.一般来说,运行UI线程时采用UI上下文,处理ASP.NET请求时采用ASP.NET请求上下文,其它很多情况则采用线程池上下文。" 这句话已经基本讲明了其实后续代码会下上文中执行。这个上下文一般时UI上下文(运行在UI上)或请求上下文(ASP.NET) 这两个可以说时原始上下文,而其它情况采用线程池上下文,也就是开辟一个新线程。这么说也就是ConfigureAwait方法是将后续代码是送到原始上下文还是线程池上下文中

下面稍微修改下刚才的方法

代码语言:javascript
复制
async Task DemoAsync()
        {
            //将后续代码交给线程池执行
            await Task.Run(() => { Thread.Sleep(3000); }).ConfigureAwait(false);
            Thread.Sleep(3000);
        }

我们使用ConfigureAwait将后续代码交给线程池来执行,也就是下面的Thread.Sleep并不会阻塞窗体.运行后发现结果也是如我们所想,

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-02-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  •    1.Await为什么不会导致堵塞   
  •  2.ConfigureAwait方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档