Asp.net

使用“非同步”(即使它應該完成)作為 MVC 路由的一部分會使路由死鎖;如何避免這種情況?

  • November 29, 2012

考慮以下(基於預設的 MVC 模板),它是在後台發生的一些“東西”的簡化版本 - 它完成得很好,並顯示了預期的結果,20:

public ActionResult Index()
{
   var task = SlowDouble(10);
   string result;
   if (task.Wait(2000))
   {
       result = task.Result.ToString();
   }
   else
   {
       result = "timeout";
   }

   ViewBag.Message = result;
   return View();
}
internal static Task<long> SlowDouble(long val)
{
   TaskCompletionSource<long> result = new TaskCompletionSource<long>();
   ThreadPool.QueueUserWorkItem(delegate
   {
       Thread.Sleep(50);
       result.SetResult(val * 2);
   });
   return result.Task;
}

但是,現在如果我們async在混合中添加一些:

public static async Task<long> IndirectSlowDouble(long val)
{
   long result = await SlowDouble(val);

   return result;
}

並將路線中的第一行更改為:

var task = IndirectSlowDouble(10);

然後它不起作用;它會超時。如果我們添加斷點,方法中的return result;inasync只會在路由已經完成之後發生- 基本上,系統似乎不願意使用任何執行緒來恢復async操作,直到請求完成之後。更糟糕的是:如果我們使用過.Wait()(或訪問過.Result),那麼它將完全死鎖。

那麼:那是怎麼回事?明顯的解決方法是“不涉及”,但這在使用庫等時並不容易。最終,和之間async沒有功能差異(儘管存在明顯的結構差異)。SlowDouble``IndirectSlowDouble

注意:控制台/winform/等中完全相同的東西可以正常工作。

這與在 ASP.NET(Pre .NET 4.5)中實現同步上下文的方式有關。關於這種行為有很多問題:

Task.WaitAll 在 ASP.NET 中掛起多個等待任務

Asp.net SynchronizationContext 為非同步延續鎖定 HttpApplication?

在 ASP.NET 4.5 中,本文介紹了同步上下文的新實現。

<http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx>

引用自:https://stackoverflow.com/questions/13621647