簡體   English   中英

為什么不等待 Task.Run() 同步回 UI 線程/源上下文?

[英]Why doesn't await Task.Run() sync back to UI Thread / origin context?

我以為我了解異步等待模式Task.Run操作。
但我想知道為什么在下面的代碼示例中,從完成的任務返回后, await沒有同步回 UI 線程。

public async Task InitializeAsync()
{
    Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}"); // "Thread: 1"
    double value = await Task.Run(() =>
    {
        Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}"); // Thread: 6

        // Do some CPU expensive stuff
        double x = 42;
        for (int i = 0; i < 100000000; i++)
        {
            x += i - Math.PI;
        }
        return x;
    }).ConfigureAwait(true);
    Console.WriteLine($"Result: {value}");
    Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}"); // Thread: 6  - WHY??
}

此代碼在帶有附加 Visual Studio 2019 調試器的 Windows 10 系統上的 .NET Framework WPF 應用程序中運行。
我從我的App類的構造函數中調用此代碼。

public App()
{
    this.InitializeAsync().ConfigureAwait(true);
}

也許這不是最好的方法,但我不確定這是否是奇怪行為的原因。

代碼從 UI 線程開始,應該執行一些任務。 通過await操作和任務完成后的ConfigureAwait(true) ,它應該在主線程 (1) 上繼續。 但事實並非如此。

為什么?

這是一件棘手的事情。

您正在 UI 線程上調用await ,這是真的。 但! 您正在App的構造函數中執行此操作。

請記住,隱式生成的啟動代碼如下所示:

public static void Main()
{
    var app = new YourNamespace.App();
    app.InitializeComponent();
    app.Run();
}

用於返回主線程的事件循環僅作為Run執行的一部分Run 所以在App構造函數運行期間,沒有事件循環。 然而。

因此,在技術上負責在await之后將流返回到主線程的SynchronizationContext在 App 的構造函數中為null

SynchronizationContextawait之前await捕獲,所以完成Task已經有一個有效的SynchronizationContext並不重要:捕獲的值為null ,因此await繼續在線程池線程上執行。)

所以問題不在於您在構造函數中運行代碼,問題在於您在App的構造函數中運行它,此時應用程序尚未完全設置好以供執行。 MainWindow的構造函數中的相同代碼將表現良好。

讓我們做一些實驗:

public App()
{
    Console.WriteLine($"sc = {SynchronizationContext.Current?.ToString() ?? "null"}");
}

protected override void OnStartup(StartupEventArgs e)
{
    Console.WriteLine($"sc = {SynchronizationContext.Current?.ToString() ?? "null"}");
    base.OnStartup(e);
}

第一個輸出給出

sc = null

第二

sc = System.Windows.Threading.DispatcherSynchronizationContext

所以你可以看到在OnStartup中已經有一個同步上下文。 因此,如果您將InitializeAsync()移動到OnStartup ,它將按照您的預期運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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