又踩.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. Timeoutat 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() 调用异步方法,死锁问题依旧。
原文地址:http://www.cnblogs.com/dudu/p/6251266.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
又踩.NET Core的坑:在同步方法中调用异步方法Wait时发生死锁(deadlock)相关推荐
- java同步调用异步方法_关于同步方法里面调用异步方法的探究
##前言 我在写代码的时候(.net core)有时候会碰到void方法里,调用async方法并且Wait,而且我还看到别人这么写了.而且我这么写的时候,编译器没有提示任何警告.但是看了dudu的文章 ...
- React 记坑 ----- 关于 react-redux 中共享状态更新时自动重新 render 页面的问题
自动重新 render 的触发条件 组件中的 render 方法内 return 部分使用了共享状态数据 通过 reducer 改变了共享状态数据的值 遇到的问题 import { ADD_PERSO ...
- 一码阻塞,万码等待:ASP.NET Core 同步方法调用异步方法“死锁”的真相
在我们 2015 年开始的从 .NET Framework 向 .NET Core 迁移的工程中,遇到的最大的坑就是标题中所说的--同步方法中调用异步方法发生"死锁".虽然在 .N ...
- channelread0会被调用两次_值得一看:C#同步方法中如何调用异步方法?
前言 我在写代码的时候(.net core)有时候会碰到void方法里,调用async方法并且Wait,而且我还看到别人这么写了.而且我这么写的时候,编译器没有提示任何警告.但是看了dudu的文章:一 ...
- 如何在C#中从同步方法调用异步方法?
我有一个public async void Foo()方法,我想从同步方法中调用它. 到目前为止,我从MSDN文档中看到的所有内容都是通过异步方法调用异步方法,但是我的整个程序不是使用异步方法构建的. ...
- java子类调用抽象父类方法_【坑】Spring中抽象父类属性注入,子类调用父类方法使用父类注入属性...
运行环境 idea 2017.1.1 spring 3.2.9.RELEASE 需求背景 需要实现一个功能,该功能有2个场景A.B,大同小异 抽象一个抽象基类Base,实现了基本相同的方法BaseMe ...
- (转)Redis上踩过的一些坑-美团
上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DBA负责人侯军伟给大家介绍了美团网在redis上踩得一些坑,讲的都是干货和坑. 分为5个部分: 一.周期性出现connect t ...
- Redis上踩过的一些坑-美团
上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DBA负责人侯军伟给大家介绍了美团网在redis上踩得一些坑,讲的都是干货和坑. 分为5个部分: 一.周期性出现connect t ...
- net core mysql 连接池_EF Core 小坑:DbContextPool 会引起数据库连接池连接耗尽
EF Core 小坑:DbContextPool 会引起数据库连接池连接耗尽 发布时间:2019-02-18 22:05, 浏览次数:1152 , 标签: EF Core DbContextPool ...
最新文章
- WebBrowser(超文本浏览框)控件默认使用IE9,IE10的方法
- Go 语言的%d,%p,%v等占位符的使用
- SAP CRM WebClient UI的configuration按钮是否显示,取决于这个权限检查
- 反卷积(Deconvolution)、上采样(UNSampling)与上池化(UnPooling)加入自己的思考(pytorch函数)(二)
- python判断密码强度并输出_Python实现的密码强度检测器示例
- eclipse项目如何变成web项目_Eclipse中将Java项目转换成Web项目的方法
- 一、Nginx源码安装与yum安装
- android开发目录结构说明
- Guacamole之本地安装Guacamole(二)
- python基础-数据类型与基本操作
- 【English】二、It作为代词,可以代指什么
- 最新版本Hadoop面试题
- WEB前端网页设计-Bootstrap 按钮下拉菜单
- java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
- 就这一篇,计算机网络基础知识总结
- 20个免费和开源数据可视化工具
- 夸克缓存视频合并小工具
- android 5.1感叹号,android 5.1 WIFI图标上的感叹号及其解决办法
- 开心词典 2006 是什么
- 计算机如何考职称英语,计算机专业考职称英语