又踩.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跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/327097.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jvm类加载器以及双亲委派

转载自 jvm类加载器以及双亲委派 首先来了解几个概念&#xff1a; 类加载&#xff1a; 概念&#xff1a;虚拟机把描述类的数据从Class文件加载到内存&#xff0c;并对数据进行校验--转换解析--初始化&#xff0c;最终形成能被java虚拟机直接使用的java类型&#xff0c;就是jvm…

java实现人脸识别源码【含测试效果图】——实体类(Users)

/** * Title: Users.java * Package org.entity * Description: TODO该方法的主要作用&#xff1a; * author A18ccms A18ccms_gmail_com * date 2017-9-22 下午7:01:09 * version V1.0 */ package org.entity;/** * * 项目名称&#xff1a;test_face_photo * 类名…

对字符进行转义

“|”、“.”、“*”、“”、“\”等不是有效的模式匹配规则表达式&#xff0c;是转义字符&#xff0c;使用split()方法时必须得加"\"才行。

分布式系统搭建:服务发现揭秘

CAP理论 加州大学终身教授与著名计算机科学家Eric Allen Brewer在90年代末提出了CAP理论&#xff0c;理论断言任一个基于网络的分布式系统&#xff0c;最多只能满足“数据一致性”、“可用性”、“分区容错性”三要素中的两个要素。 该理论后被MIT证明可行&#xff0c;故架构师…

SSL / TLS 协议运行机制详解

转载自 SSL / TLS 协议运行机制详解 互联网的通信安全&#xff0c;建立在SSL/TLS协议之上。 本文简要介绍SSL/TLS协议的运行机制。文章的重点是设计思想和运行过程&#xff0c;不涉及具体的实现细节。如果想了解这方面的内容&#xff0c;请参阅RFC文档。 一、作用 不使用SS…

java实现人脸识别源码【含测试效果图】——Dao层(BaseDao)

package org.dao;import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List;/*** * * 项目名称&#xff1a;test_face_photo * 类名称&#…

统计单词出现的次数并进行排

统计 统计相同单词的次数 //使用map集合进行存储 String s"Day by Day"; Map<String,Integer> mapnew HashMap<String,Integer>(); StringTokenizer tokenizernew StringTokenizer(s); int count;//记录次数 String word;//单个单词 while(tokenizer.ha…

Mybatisplus 自动生成字段 强制覆盖 null或者空字符串也覆盖

ApiModelProperty(value "证件号码&#xff0c;现在是身份证号") TableField("id_number") private String idNumber;ApiModelProperty(value "证件到期日期") TableField(value "id_card_expire_date",fill FieldFill.UPDATE) priv…

在ASP.NET Core Web API上使用Swagger提供API文档

我在开发自己的博客系统&#xff08;http://daxnet.me&#xff09;时&#xff0c;给自己的RESTful服务增加了基于Swagger的API文档功能。当设置IISExpress的默认启动路由到Swagger的API文档页面后&#xff0c;在IISExpress启动Web API站点后&#xff0c;会自动重定向到API文档页…

一文告诉你 Java RMI 和 RPC 的区别

转载自 一文告诉你 Java RMI 和 RPC 的区别 RPC 远程过程调用 RPC&#xff08;Remote Procedure Call Protocol&#xff09;远程过程调用协议&#xff0c;通过网络从远程计算机上请求调用某种服务。一次RPC调用的过程大概有10步&#xff1a; 1.执行客户端调用语句&#xff…

java实现人脸识别源码【含测试效果图】——Dao层(IBaseDaoUtil)

/*** */ package org.dao;/*** * * 项目名称&#xff1a;test_face_photo * 类名称&#xff1a;IBaseDaoUtil * 类描述&#xff1a; 共用接口 * 创建人&#xff1a;Mu Xiongxiong * 创建时间&#xff1a;2017-9-22 下午6:59:36 * 修改人&#xff1a;Mu Xiong…

stream 提取某字段_java8从list集合中取出某一属性的值的集合案例

List orderNoListlist.stream().map(Order::getOrderNo).collect(Collectors.toList()); https://blog.csdn.net/weixin_39702400/article/details/111895006 我就废话不多说了&#xff0c;大家还是直接看代码吧~ List list new ArrayList(); Order o1 new Order("1&q…

线程VS进程

什么是线程、什么是进程 在Java中要同时执行&#xff08;如果是单核&#xff0c;准确的说是交替执行&#xff09;多个任务&#xff0c;使用的是多线程&#xff0c;而要理解线程&#xff0c;我们先要了解什么是进程什么是线程。 一般的定义&#xff1a;进程是指在操作系统中正在…

Java架构师必须知道的 6 大设计原则

转载自 Java架构师必须知道的 6 大设计原则 在软件开发中&#xff0c;前人对软件系统的设计和开发总结了一些原则和模式&#xff0c; 不管用什么语言做开发&#xff0c;都将对我们系统设计和开发提供指导意义。本文主要将总结这些常见的原则&#xff0c;和具体阐述意义。 开发…

java实现人脸识别源码【含测试效果图】——Dao层(IUserDao)

/** * Title: IUserDao.java * Package org.dao * Description: TODO该方法的主要作用&#xff1a; * author A18ccms A18ccms_gmail_com * date 2017-9-22 下午8:51:34 * version V1.0 */ package org.dao;import org.entity.Users;/** * * 项目名称&#xff1a;te…

Flux --gt; Redux --gt; Redux React 入门 基础实例教程

本文的目的很简单&#xff0c;介绍Redux相关概念用法 及其在React项目中的基本使用 假设你会一些ES6、会一些React、有看过Redux相关的文章&#xff0c;这篇入门小文应该能帮助你理一下相关的知识 一般来说&#xff0c;推荐使用 ES6ReactWebpack 的开发模式&#xff0c;但Webpa…

mybatisplus 强制制空 空覆盖原来的字符串

ApiModelProperty(value "证件照片url") TableField(value "id_photo_url",fill FieldFill.UPDATE) private String idPhotoUrl; 方法一 Data EqualsAndHashCode(callSuper false) Accessors(chain true) TableName("base_party_member") A…

Callable和Future

它们俩其实挺有意思&#xff0c;在运行的时候各司其职&#xff0c;Callable产生结果&#xff0c;Future获取结果。 使用步骤如下&#xff1a; 创建 Callable 接口的实现类&#xff0c;并实现 call() 方法&#xff0c;该 call() 方法将作为线程执行体&#xff0c;并且有返回值…

java实现人脸识别源码【含测试效果图】——DaoImpl层(BaseDaoUtilImpl)

/*** */ package org.dao.impl;import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List;import org.dao.BaseDao; import org.entity.Users; import org.junit.Test;/*** * * 项目名称&#xff1a;test_BaseDao …

90 % Java 程序员被误导的一个性能优化策略

转载自 90 % Java 程序员被误导的一个性能优化策略 我们经常看到一些 Java 性能优化的书或者理念&#xff0c;说不要在循环内定义变量&#xff0c;这样会占用过多的内存影响性能&#xff0c;而要在循环外面定义。接触 Java 这么久以来&#xff0c;相信很多 Java 程序员都被这…