随意使用异步的await和Result,被弄得欲仙欲死,然后看了 Don't Block on Async Code,稍许明白,翻译然后加上自己的理解以加深印象。

会死锁的两个例子

UI例子

    public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
} // My "top-level" method.
public void Button1_Click(...)
{
var jsonTask = GetJsonAsync(...);
textBox1.Text = jsonTask.Result;
}

** ASP.NET例子**

    public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
} // My "top-level" method.
public class MyController : ApiController
{
public string Get()
{
var jsonTask = GetJsonAsync(...);
return jsonTask.Result.ToString();
}
}

死锁的原因

await 一个Task后,当Task完成后将继续一个Context。

UI例子的content是 UI content,ASP.NET例子的Content是request content。在任何时候,这两个content只能属于一个线程,是不能被具体的线程捆绑(tied)。这个有趣或者恶心的特色没被官方文档说明,只在my MSDN article about SynchronizationContext

上面两个例子的运行过程是:

  1. 在UI/ASP.NET context,调用GetJsonAsync方法;
  2. 在UI/ASP.NET context,GetJsonAsync方法调用HttpClient.GetStringAsync开始一个REST请求;
  3. GetStringAsync返回一个未完成的Task,表示REST请求没有完成;
  4. GetJsonAsync等待GetStringAsync返回的Task。当前Context被捕获(保存),当前Context在GetJsonAsync完成时将被调用。GetJsonAsync返回一个未完成的Task,表示GetJsonAsync方法未完成;
  5. jsonTask.Result同步阻塞GetJsonAsync返回的任务,即阻塞context;
  6. ...然后,REST请求完成了,然后通知GetStringAsync方法;
  7. GetStringAsync准备继续任务,他等待context可用,然后他可以在context运行;
  8. 死锁!jsonTask.Result阻塞了context线程,等待GetStringAsync完成,GetStringAsync等待context空闲,然后它可以完成。

防止死锁

两点经验:

  1. 异步方法中,尽可能添加*ConfigureAwait(false) *;
  2. 别阻塞;使用 async

根据第一点经验:

var jsonString = await client.GetStringAsync(uri);

改成

var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);

根据第二点经验,调用异步方法的代码如下:

    public async void Button1_Click(...)
{
var json = await GetJsonAsync(...);
textBox1.Text = json;
} public class MyController : ApiController
{
public async Task<string> Get()
{
var json = await GetJsonAsync(...);
return json.ToString();
}
}

await 是一个异步等待

.Result是一个同步等待

同步等待在控制台程序、单元测试中不会死锁

最新文章

  1. View and Data API Tips : Conversion between DbId and node
  2. 阿里云安装LNMP以及更改网站文件和MySQL数据目录
  3. [Android Pro] Java进阶学习:jar打包详解
  4. js判断手机端Android手机还是iPhone手机
  5. Entity FrameWork对有外键关联的数据表的添加操作
  6. HTML5 对于手机页面长按会粘贴复制的禁用 (解决方案)
  7. 引擎设计跟踪(九.14.2i) Android GLES 3.0 完善
  8. JavaScript之获取和设置元素属性
  9. angular实战
  10. 实验吧Web-天网管理系统
  11. frameset导航框架
  12. js date相关学习!
  13. L6,Percy Buttons
  14. Coursera Deep Learning 2 Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization - week2, Optimization algorithms
  15. maven scope使用和理解
  16. ViZDoom深度预测(Depth Prediction)
  17. keras后端设置【转载】
  18. 2018.10.26 NOIP模拟 瓶子 (dp/贪心)
  19. 拥抱Service Fabric &mdash;&mdash; 目录
  20. javascript的简单查询和插入和修改

热门文章

  1. CentOS7.X怎样更新yum源
  2. winform使用log4.net
  3. POJ 3616 奶牛挤奶
  4. 1.1 Django起步
  5. 又谈T检验
  6. Python自学:第三章 使用方法sort( )对列表进行永久性排序
  7. SpringBoot之Java配置
  8. dedecmsV5.7和discuz!X3.4整合之后免激活登陆
  9. 因为没有安装xcode,得不到xcode证书报错
  10. .gitconfig