随意使用异步的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. C# 如何获取可执行文件路径的上上级目录

    1. DirectoryInfo di = new DirectoryInfo(string.Format(@"{0}..\..\", Application.StartupPat ...

  2. 【MVC】ASP.NET MVC之数据验证

    前端传到后端数据的不可信任性,DRY("Don't Repeat Yourself") 设计原则.MVC3.0出了后端数据验证特性,鼓励你只定义一次功能或行为,然后在应用程序中各处 ...

  3. element-UI——el-table添加序号

    转载自:https://www.cnblogs.com/langxiyu/p/10641060.html Part.1 示例 当我们想在 el-table 中添加序号列时,如下: <el-tab ...

  4. MySQL中Decimal类型和Float Double的区别 & BigDecimal与Double使用场景

    MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,float,double等非标准类型,在DB中保存的是近似值,而Decimal则以字符串的形 ...

  5. .NetCore WebApi 添加 Log4Net

    一 .配置 1.vs2019 创建一个.net core web程序,选择webapi 2.项目中添加一个配置文件:添加--新建项--XML文件,命名为log4net.config 我使用的是log4 ...

  6. spring cloud(四)熔断器Hystrix

    熔断器 雪崩效应 在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应.服务雪崩效应是一种因“服务提供者”的不可用导致“服务 ...

  7. JCache只缓存部分字段

    项目中使用的JCache缓存实体,发现每次缓存时存进去了实体,取出的时候字段有些是空的. 具体环境为 Springboot v2.01 JCache(ehcache 3.4.0) jdk 1.8.0_ ...

  8. promise用法十道题

    JS是单线程语言,多数的网站不需要大量计算,程序耗时主要是在磁盘I/O和网络I/O上 ,虽然固态硬盘SSD读取很快,但是和CPU比起来却不在一个数量级上,而且网络上的一个数据包来回时间更慢,所以一些C ...

  9. Java IO编程全解(四)——NIO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7793964.html 前面讲到:Java IO编程全解(三)——伪异步IO编程 NIO,即New I/O,这 ...

  10. WEEK1

    #变量 var1: name = input('name:') age = input('age:) job = input('job:) salary = input('salary:) info ...