Asp.net
使用“非同步”(即使它應該完成)作為 MVC 路由的一部分會使路由死鎖;如何避免這種情況?
考慮以下(基於預設的 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>