日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

又踩.NET Core的坑:在同步方法中调用异步方法Wait时发生死锁(deadlock)

發布時間:2023/12/4 asp.net 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 又踩.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)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。