簡體   English   中英

單行異步方法SynchronizationContext

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM