之前在将 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)相关推荐

  1. java同步调用异步方法_关于同步方法里面调用异步方法的探究

    ##前言 我在写代码的时候(.net core)有时候会碰到void方法里,调用async方法并且Wait,而且我还看到别人这么写了.而且我这么写的时候,编译器没有提示任何警告.但是看了dudu的文章 ...

  2. React 记坑 ----- 关于 react-redux 中共享状态更新时自动重新 render 页面的问题

    自动重新 render 的触发条件 组件中的 render 方法内 return 部分使用了共享状态数据 通过 reducer 改变了共享状态数据的值 遇到的问题 import { ADD_PERSO ...

  3. 一码阻塞,万码等待:ASP.NET Core 同步方法调用异步方法“死锁”的真相

    在我们 2015 年开始的从 .NET Framework 向 .NET Core 迁移的工程中,遇到的最大的坑就是标题中所说的--同步方法中调用异步方法发生"死锁".虽然在 .N ...

  4. channelread0会被调用两次_值得一看:C#同步方法中如何调用异步方法?

    前言 我在写代码的时候(.net core)有时候会碰到void方法里,调用async方法并且Wait,而且我还看到别人这么写了.而且我这么写的时候,编译器没有提示任何警告.但是看了dudu的文章:一 ...

  5. 如何在C#中从同步方法调用异步方法?

    我有一个public async void Foo()方法,我想从同步方法中调用它. 到目前为止,我从MSDN文档中看到的所有内容都是通过异步方法调用异步方法,但是我的整个程序不是使用异步方法构建的. ...

  6. java子类调用抽象父类方法_【坑】Spring中抽象父类属性注入,子类调用父类方法使用父类注入属性...

    运行环境 idea 2017.1.1 spring 3.2.9.RELEASE 需求背景 需要实现一个功能,该功能有2个场景A.B,大同小异 抽象一个抽象基类Base,实现了基本相同的方法BaseMe ...

  7. (转)Redis上踩过的一些坑-美团

    上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DBA负责人侯军伟给大家介绍了美团网在redis上踩得一些坑,讲的都是干货和坑. 分为5个部分: 一.周期性出现connect t ...

  8. Redis上踩过的一些坑-美团

    上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DBA负责人侯军伟给大家介绍了美团网在redis上踩得一些坑,讲的都是干货和坑. 分为5个部分: 一.周期性出现connect t ...

  9. net core mysql 连接池_EF Core 小坑:DbContextPool 会引起数据库连接池连接耗尽

    EF Core 小坑:DbContextPool 会引起数据库连接池连接耗尽 发布时间:2019-02-18 22:05, 浏览次数:1152 , 标签: EF Core DbContextPool ...

最新文章

  1. WebBrowser(超文本浏览框)控件默认使用IE9,IE10的方法
  2. Go 语言的%d,%p,%v等占位符的使用
  3. SAP CRM WebClient UI的configuration按钮是否显示,取决于这个权限检查
  4. 反卷积(Deconvolution)、上采样(UNSampling)与上池化(UnPooling)加入自己的思考(pytorch函数)(二)
  5. python判断密码强度并输出_Python实现的密码强度检测器示例
  6. eclipse项目如何变成web项目_Eclipse中将Java项目转换成Web项目的方法
  7. 一、Nginx源码安装与yum安装
  8. android开发目录结构说明
  9. Guacamole之本地安装Guacamole(二)
  10. python基础-数据类型与基本操作
  11. 【English】二、It作为代词,可以代指什么
  12. 最新版本Hadoop面试题
  13. WEB前端网页设计-Bootstrap 按钮下拉菜单
  14. java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
  15. 就这一篇,计算机网络基础知识总结
  16. 20个免费和开源数据可视化工具
  17. 夸克缓存视频合并小工具
  18. android 5.1感叹号,android 5.1 WIFI图标上的感叹号及其解决办法
  19. 开心词典 2006 是什么
  20. 计算机如何考职称英语,计算机专业考职称英语

热门文章

  1. 链表笔试题汇编(一)
  2. MFC多语言实现方法
  3. 在U盘上安装linux
  4. ASP.NET Core使用功能开关控制路由访问
  5. 这次使用一个最舒服的姿势插入HttpClient拦截器技能点
  6. 基于事件驱动架构构建微服务第5部分:容器化(Web Api Core 和 SQL Server Linux)
  7. .net core ——利用 roslyn 编译C#代码
  8. 基于ABP落地领域驱动设计-04.领域服务和应用服务的最佳实践和原则
  9. 阿里25k招.NET,要求WPF!
  10. Dotnet的数据定位和匹配