[英]One-line async method SynchronizationContext
我准備了WinForms應用程序,以測試單行異步方法是否會導致死鎖。 button1_Click
事件等待單行異步代理方法等待的GetZero
任務。 但是,它導致死鎖。 為什么? 我已經讀過,單行異步方法不需要在await
完成后繼續執行任何操作,因此沒有委托可以將消息發送到導致死鎖的消息泵。
作為參考, button2_Click
事件在沒有代理調用方的情況下等待任務GetZero
的結果,並且應用程序可以正常工作。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var zero = ProxyCallery().Result;
label1.Text += $"{zero}";
}
private void button2_Click(object sender, EventArgs e)
{
var zero = GetZero().Result;
label1.Text += $"{zero}";
}
private async Task<int> ProxyCallery()
{
return await GetZero();
}
private async Task<int> GetZero()
{
await Task.Delay(100).ConfigureAwait(false);
return await Task.FromResult(0);
}
}
為什么button1_Click
導致死鎖?
await Task.Delay(100).ConfigureAwait(false);
只為該呼叫配置等待。 它不會影響可能依賴於該特定await GetZero()
,例如ProxyCallery()
方法中的ProxyCallery()
。
后一種等待仍然需要UI線程中的繼續,您已使用ProxyCallery().Result
阻止了該線程。 因此陷入僵局。
我已經讀過,單行異步方法不需要在等待完成后繼續執行任何操作,因此沒有委托可以將消息發送到導致死鎖的消息泵。
我不知道你在哪里讀的書,但這是錯誤的。 編譯器不會嘗試優化“ tail awaits”。 實際上,即使方法中的最后一件事是await
,仍然有繼續執行的代碼。 至少,解開任何異常,還要將延續傳播到該async
方法表示的Task
。
因此,對於斷定方法的await
語句,與在方法的其他任何地方找到的await
語句相比, await
死鎖或異步執行的任何其他方面完全沒有區別。
您的ProxyCallery
實際上是兩行,就異步操作之后的意義而言, 是連續的:
private async Task<int> ProxyCallery()
{
var zero = await GetZero();
return zero; // <-- continuation!
}
繼續是返回任務的結果 !
當前,上述延續與Task.Delay
任務的延續不在同一同步上下文中,這是導致死鎖的原因。
您創建的每個任務都應在相同的同步上下文中!
private async Task<int> ProxyCallery()
{
var zero = await GetZero().ConfigureAwait(false);
return zero;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.