我正在閱讀這篇文章并找到了這個例子:
public static class DeadlockDemo
{
private static async Task DelayAsync()
{
await Task.Delay(1000);
}
// This method causes a deadlock when called in a GUI or ASP.NET context.
public static void Test()
{
// Start the delay.
var delayTask = DelayAsync();
// Wait for the delay to complete.
delayTask.Wait();
}
}
這種死鎖的根本原因是由于 await 處理背景關系的方式。默認情況下,當等待一個未完成的任務時,當前的“背景關系”被捕獲并用于在任務完成時恢復方法。這個“背景關系”是當前的 SynchronizationContext 除非它是空的,在這種情況下它是當前的 TaskScheduler。GUI 和 ASP.NET 應用程式有一個 SynchronizationContext,它一次只允許運行一個代碼塊。當 await 完成時,它會嘗試在捕獲的背景關系中執行異步方法的其余部分。但是該背景關系中已經有一個執行緒,它(同步)等待異步方法完成。他們都在等待對方,導致僵局。
我知道如果在 之后有代碼await Task.Delay(1000);,它將成為延續的一部分,并且延續將在與 相同的背景關系中運行Test(),這就是死鎖的發生方式。
然而,沒有延續,那么死鎖究竟是如何發生的呢?
或者,是否創建了一個空的延續?那有什么意義呢?
這是讓我困惑的部分:
當 await 完成時,它會嘗試在捕獲的背景關系中執行異步方法的其余部分。
什么是“異步方法的剩余部分”?
uj5u.com熱心網友回復:
如果我們是一個async Taskorasync Task<T>方法,那么在之后總是有作業要做await——我們需要確保awaited 任務產生的任何例外都正確地傳播到我們自己的Task,或者我們傳遞了適當的正常回傳值。
如果我們是async使用結構的任何型別的方法,例如using將編譯器生成的代碼插入到我們的方法中,否則我們將在方法的末尾插入代碼,即使它沒有“ t 出現在來源中。
如果我們是任意async使用awaits 的任何普通方法,那么我們已經構建并運行了一個狀態機來執行我們的方法,并且優化“最后一次等待后沒有代碼”的可能性沒有意義。
在狹義的情況下,我們是一個最后包含單個方法的async void1方法await,然后除了一些關于可能報告任務未處理例外的細節之外,我們已經有機會通過不使方法async,只是忽略了可等待的。
所以沒有理由嘗試優化這種情況。
1無論如何,我們那時已經處于罪惡狀態。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/318802.html
