又踩.NET Core的坑:在同步方法中调用异步方法Wait时发生死锁(deadlock)
之前在将 Memcached 客户端 EnyimMemcached 迁移 .NET Core 时被这个“坑”坑的刻骨铭心(详见以下链接),当时以为只是在构造函数中调用异步方法(注:这里的异步方法都是指基于Task的)才会出线死锁(deadlock)问题。
- 解决 .NET Core 中 GetHostAddressesAsync 引起的 EnyimMemcached 死锁问题
- 在同步方法中调用异步方法时如何避免死锁问题
- .NET Core中遇到奇怪的线程死锁问题:内存与线程数不停地增长
- 尝试解决在构造函数中同步调用Dns.GetHostAddressesAsync()引起的线程死锁
最近在使用 redis 客户端 StackExchange.Redis 时也遇到了这个问题, 详见 ASP.NET Core中StackExchange.Redis连接redis服务器的问题 。
StackExchange.Redis 中死锁问题发生在下面的代码:
private static ConnectionMultiplexer ConnectImpl(Func<ConnectionMultiplexer> multiplexerFactory, TextWriter log)
{
IDisposable killMe = null;
try
{
var muxer = multiplexerFactory();
killMe = muxer;
// note that task has timeouts internally, so it might take *just over* the regular timeout
var task = muxer.ReconfigureAsync(true, false, log, null, "connect"); if (!task.Wait(muxer.SyncConnectTimeout(true)))
{
task.ObserveErrors();
if (muxer.RawConfig.AbortOnConnectFail)
{
throw ExceptionFactory.UnableToConnect("Timeout");
}
}
if (!task.Result) throw ExceptionFactory.UnableToConnect(muxer.failureMessage);
killMe = null;
return muxer;
}
finally
{
if (killMe != null) try { killMe.Dispose(); } catch { }
}
}
ConnectImpl() 是一个同步方法,muxer.ReconfigureAsync() 是一个 async 异步方法。在 Linux 上运行时, task.Wait(muxer.SyncConnectTimeout(true)) 会因为等待超时而返回 false ,从而出现下面的错误:
StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. Timeout
at StackExchange.Redis.ConnectionMultiplexer.ConnectImpl(Func`1 multiplexerFactory, TextWriter log)
如果改为 task.Wait() ,在 ASP.NET Core 程序中调用时,请求会因为死锁而卡死。
这是一个典型的同步方法调用异步方法在 Wait 时的死锁问题(详见 Don't Block on Async Code),通常的解决方法是使用 .ConfigureAwait(false); (异步任务执行完成时不获取SynchronizationContext)。StackExchange.Redis 的开发者当然知道这一点,在 muxer.ReconfigureAsync() 中调用每一个异步方法时都加上了 .ConfigureAwait(false); 。但我们遇到的实际情况显示,这一招在 .NET Framework 中管用,在 .NET Core 中却不管用,这可能与 .NET Core 在异步机制上的改变有关,比如在异步方法中 System.Threading.SynchronizationContext.Current 的值总是为 null ,详见 ASP.NET Core 1.0 SynchronizationContext 。
这个问题在 Liunx 上很容易出现,而在 Windows 上需要一定的并发请求才会出现。
后来在 Microsoft.AspNetCore.DataProtection.AzureStorage 中也发现了在同步方法中调用异步方法的代码:
public IReadOnlyCollection<XElement> GetAllElements()
{
var blobRef = CreateFreshBlobRef(); // Shunt the work onto a ThreadPool thread so that it's independent of any
// existing sync context or other potentially deadlock-causing items. var elements = Task.Run(() => GetAllElementsAsync(blobRef)).GetAwaiter().GetResult();
return new ReadOnlyCollection<XElement>(elements);
}
参考上面的代码,在 StackExchange.Redis 中的 ConnectImpl() 方法中改为 Task.Run() 调用异步方法,死锁问题依旧。
又踩.NET Core的坑:在同步方法中调用异步方法Wait时发生死锁(deadlock)的更多相关文章
- (转)为什么wait(),notify()和notifyAll()必须在同步块或同步方法中调用
我们常用wait(),notify()和notifyAll()方法来进行线程间通信.线程检查一个条件后就行进入等待状态,例如,在“生产者-消费者”模型中,生产者线程发现缓冲区满了就等待,消费者线程通过 ...
- 一码阻塞,万码等待:ASP.NET Core 同步方法调用异步方法“死锁”的真相
在我们 2015 年开始的从 .NET Framework 向 .NET Core 迁移的工程中,遇到的最大的坑就是标题中所说的--同步方法中调用异步方法发生"死锁".虽然在 .N ...
- 【坑】Spring中抽象父类属性注入,子类调用父类方法使用父类注入属性
运行环境 idea 2017.1.1 spring 3.2.9.RELEASE 需求背景 需要实现一个功能,该功能有2个场景A.B,大同小异 抽象一个抽象基类Base,实现了基本相同的方法BaseMe ...
- 深入理解 EF Core:EF Core 写入数据时发生了什么?
阅读本文大概需要 14 分钟. 原文:https://bit.ly/2C67m1C 作者:Jon P Smith 翻译:王亮 声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的.其中可能 ...
- Redis上踩过的一些坑
来自: http://blog.csdn.net//chenleixing/article/details/50530419 上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DB ...
- [转帖]美团在Redis上踩过的一些坑-1.客户端周期性出现connect timeout
美团在Redis上踩过的一些坑-1.客户端周期性出现connect timeout 博客分类: redis 运维 jedisconnect timeoutnosqltcp 转载请注明出处哈:http ...
- 三分之一的程序猿之社交类app踩过的那些坑
三分之一的程序猿之社交类app踩过的那些坑 万众创新,全民创业.哪怕去年陌生人社交不管融资与否都倒闭了不知道多少家,但是依然有很多陌生人社交应用层出不穷的冒出来.各种脑洞大开,让人拍案叫起. 下面我们 ...
- 【Fine原创】JMeter分布式测试中踩过的那些坑
最近因为项目需要,研究了性能测试的相关内容,并且最终选用了jmeter这一轻量级开源工具.因为一直使用jmeter的GUI模式进行脚本设计,到测试执行阶段工具本身对资源的过量消耗给性能测试带来了瓶颈, ...
- 与webview打交道中踩过的那些坑
随着HTML5被越来越多的用到web APP的开发当中,webview这一个神器便日渐凸显出重要地位.简要的说,webview能够在移动应用中开辟出一个窗口,在里面显示html页面,css以及js代码 ...
随机推荐
- mongodb 启动脚本和配置
http://justcoding.iteye.com/blog/2270466 http://blog.csdn.net/neutrojan/article/details/32328531
- [BI项目记]-TFS Express备份和恢复
在项目中对TFS进行备份操作是日常重要的工作之一,此篇主要描述如何对TFS Express进行备份,并且在另外一台服务器上进行恢复. 以下是操作的几个关键点: 备份数据库,在TFS管理工具中就可以完成 ...
- [BI项目记]-BUG处理
BUG是在项目过程中以及运维过程中经常遇到的工作项.在处理每一个BUG的过程中,通过项目管理系统把BUG相应的内容纪录下来也是很重要的.这里将介绍如何通过TFS来完成BUG的处理工作. 首先看一下BU ...
- C#语言实现定时开启或禁用网卡小程序
C#语言实现定时开启/禁用网卡 程序运行效果图 程序实现主要代码 源代码工程文件(VS2013工程文件编译通过) 查看网卡名称附图 1.win7旗舰版运行效果图: 2.程序实现主要代码: /// 网卡 ...
- sql语句,怎么取查询结果的位置
SQL 中的 substring 函数是用来抓出一个栏位资料中的其中一部分.这个函数的名称在不同的资料库中不完全一样: MySQL: SUBSTR( ), SUBSTRING( ) Oracle: S ...
- Hibernate 非常见异常集合
异常一:org.hibernate.AnnotationException: Collection has neither generic type or OneToMany.targetEntity ...
- GAMBIT、ICEM、HYPERMESH耦合面的处理方法
前两天在论坛里碰到有朋友问关于使用fluent仿真流固耦合,使用hypermesh作为前处理时的耦合面的方法,刚好今天有点时间,借此机会总结一下GAMBIT.ICEM和HYPERMESH这三款软件作为 ...
- EXT5 时间框控制(开始时间不能大于结束时间)
1.网上看的大部分代码都是利用vtype : 'dateRange' EXT的这个属性,但是可能由于环境问题还是怎么样,我就是实现不了想要的效果. 然后研究了一下,在时间框的listeners 监听 ...
- linux查看是什么操作系统是什么命令
https://zhidao.baidu.com/question/361519585968730492.html
- shell脚本生成限定范围的随机数
#!/bin/bash +)) 这串代码实现了随机生成从1~50之间是数 这串代码特别简单,就是利用RANDOM这个随机数生成器进行取余就能够实现,至于为什么取余时需要+1是因为在取余时如果被整除那么 ...