随意使用异步的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是一个同步等待

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

【C#】await & Result DeadLock的更多相关文章

  1. 【Lab】提取result的bits和Y-PSNR数据并整理到Excel

    [Lab]提取result的bits和Y-PSNR数据并整理到Excel 更新:使用openpyxl库直接将数据写入Excel中 注意:openpyxl是第三方库,如果没有安装.请命令行里键入pip ...

  2. C#异步的世界【下】

    接上篇:<C#异步的世界[上]> 上篇主要分析了async\await之前的一些异步模式,今天说异步的主要是指C#5的async\await异步.在此为了方便的表述,我们称async\aw ...

  3. 【转】C#异步的世界【下】

    [转]C#异步的世界[下] 接上篇:<C#异步的世界[上]> 上篇主要分析了async\await之前的一些异步模式,今天说异步的主要是指C#5的async\await异步.在此为了方便的 ...

  4. C#异步的世界【下】(转)

    接上篇:<C#异步的世界[上]> 上篇主要分析了async\await之前的一些异步模式,今天说异步的主要是指C#5的async\await异步.在此为了方便的表述,我们称async\aw ...

  5. 【TypeScript】如何在TypeScript中使用async/await,让你的代码更像C#。

    [TypeScript]如何在TypeScript中使用async/await,让你的代码更像C#. async/await 提到这个东西,大家应该都很熟悉.最出名的可能就是C#中的,但也有其它语言也 ...

  6. 【笔记】记一次.net语法await和async的异步编程实验与笔记。

    1.实践代码全记录: using System; using System.Collections.Generic; using System.Diagnostics; using System.Li ...

  7. 【Selenium】【BugList9】windows环境,fp = open("./"+ time.strftime("%Y-%m-%d %H:%M:%S") + " result.html",'wb'),报错:OSError: [Errno 22] Invalid argument: './2018-09-05 10:29:32 result.html'

    [代码] if __name__=="__main__": suite = unittest.TestSuite() suite.addTest(Baidu("test_ ...

  8. 【锁】Oracle死锁(DeadLock)的分类及其模拟

    [锁]Oracle死锁(DeadLock)的分类及其模拟 1  BLOG文档结构图 2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不 ...

  9. 【多线程】 Task ,async ,await

    [多线程]Task ,async ,await 一. WinForm 里经常会用到多线程, 多线程的好出就不多说了,来说说多线程比较麻烦的地方 1. UI 线程与其他线程的同步,主要是 Form 和 ...

随机推荐

  1. R代码展示各种统计学分布 | 生物信息学举例

    二项分布 | Binomial distribution 泊松分布 | Poisson Distribution 正态分布 | Normal Distribution | Gaussian distr ...

  2. PPI | protein-protein interaction | 蛋白互作分析

    STRING database的挖掘 这个数据库绝对是做实验人的宝藏,里面包含了各种蛋白互作关系,不用做实验就有一大堆证据. IPA了解一下,收费的高端分析软件,大部分就是整合的这个数据库,很多大佬喜 ...

  3. ERROR:scala:Error:Object scala.runtime in compiler mirror not found

    我的项目是sbt项目,今天早晨的时候还好好的,结果中午吃了个饭回来就特么的编译就报错了,真是闹心 报错截图: 解决方案: 删除idea的缓存文件 然后重新启动idea,重新下载jia包,在进行编译,就 ...

  4. LDA(线性判别分类器)学习笔记

    Linear Discriminant Analysis(线性判别分类器)是对费舍尔的线性鉴别方法(FLD)的归纳,属于监督学习的方法. LDA的基本思想是将高维的模式样本投影到最佳鉴别矢量空间,以达 ...

  5. OO-第二单元总结

    一.三次作业的设计策略 (1). 第五次作业 第五次作业由于较为简单,在强测及互测中均没有出现BUG,但是并没有做优化.本次的设计有些不合理,所以在后面的作业中也做了重构.本次的作业主要有三个类,主函 ...

  6. es索引管理工具-curator

    elasticsearch-curator  是官方收购的开源社区周边产品,用来管理es的索引和快照. 官方文档:https://www.elastic.co/guide/en/elasticsear ...

  7. Java语言中的奇淫技巧

    variable length parameter list(可变长度参数列表) 很久之前了解过有这么一种写法,但转眼即忘.今天在公司项目的代码里看到,有点小惊讶,写这代码的同事还是有点水平的...

  8. SpringBoot使用日志

    1.日志框架 日志门面 日志实现 JCL.SLF4J.jboss-logging Log4j.JUL.Log4j2.Logback 日志门面:SLF4J 日志实现:Logback SpringBoot ...

  9. 初学Git命令

    初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 使用命令git add <file>,注意,可反复多次使用,添加多个文件: 使用命令git commit ...

  10. CentOS 7 + MySql 中文乱码解决方案

    原文:https://blog.csdn.net/qq_32953079/article/details/54629245,亲测有效,故记录之. 一.登录MySQL查看用SHOW VARIABLES ...