简体   繁体   English

任务的延续(由async / await构建)在WPF应用程序的主线程上运行,但在控制台应用程序的子线程上运行

[英]Task's continuation (built by async/await) is running on main thread in a WPF application, but on child in a console application

Assume I have a simple C# Console Application: 假设我有一个简单的C#控制台应用程序:

class Program
{
    static async void func()
    {
        Thread.CurrentThread.Name = "main";
        await Task.Run(() =>
        {
            Thread.CurrentThread.Name = "child";
            Thread.Sleep(5000);
        });
        Console.WriteLine("continuation is running on {0} thread", Thread.CurrentThread.Name);
    }

    static void Main(string[] args)
    {
        func();
        Thread.Sleep(10000);
    }
}

When 5000 ms pass, we see the "continuation is running on child thread" message. 经过5000毫秒后,我们看到“继续在子线程上运行”消息。 When another 5000 ms pass, main thread finishes its work and application is closed. 当又经过5000毫秒时,主线程完成其工作,并且应用程序关闭。 It looks rather logical: asynchronous task and its continuation are running on the same child thread. 它看起来很合乎逻辑:异步任务及其延续在同一子线程上运行。

But assume now I have a simple WPF application: 但假设现在我有一个简单的WPF应用程序:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    async private void mainWnd_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Thread.CurrentThread.Name = "main";
        await Task.Run(() =>
        {
            Thread.CurrentThread.Name = "child";
            Thread.Sleep(5000);
        });
        this.Title = string.Format("continuation is running on {0} thread", Thread.CurrentThread.Name);
    }

    private void mainWnd_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        Thread.Sleep(10000);
    }
}

Now when we press left mouse button and 5000 ms pass, we see "continuation is running on main thread" title. 现在,当我们按下鼠标左键并经过5000毫秒时,我们看到“继续在主线程上运行”标题。 Moreover, if we press left button and then right button, application first will run mainWnd_MouseLeftButtonDown handler, then mainWnd_MouseRightButtonDown handler (on main thread), main thread will sleep for 10000 ms, and then continuation of asynchronous task from mainWnd_MouseLeftButtonDown will be still performed on main thread. 此外,如果我们按下左键,然后右键,应用程序第一次运行mainWnd_MouseLeftButtonDown处理程序,然后mainWnd_MouseRightButtonDown处理程序(在主线程),主线程会睡眠10000毫秒,然后从异步任务的延续mainWnd_MouseLeftButtonDown将在主来仍然执行线。

Why does async-await mechanism differ for these two situations? 为什么这两种情况的async-await机制不同?

I know that in WPF method can be explicitly run on UI thread through Dispatcher.Invoke , but async-await mechanism isn't WPF -specific, so its behavior should be equal in any kind of application, shouldn't it? 我知道可以通过Dispatcher.InvokeWPF中显式地在UI线程上运行方法,但是async-await机制不是特定于WPF ,因此它的行为在任何类型的应用程序中都应该相等,不是吗?

Any help will be appreciated. 任何帮助将不胜感激。

async-await respects the current scope's SynchronizationContext . async-await尊重当前范围的SynchronizationContext That means that the context (if it exists) is captured when the asynchronous operation starts and when it ends the continuation is scheduled on the captured context. 这意味着在异步操作开始时捕获上下文(如果存在),并在结束时在捕获的上下文上调度继续。

UI applications ( WPF / Winforms ) use a SynchronizationContext that allows only for the main ( UI ) thread to interact with the UI elements, so it seamlessly works with async-await . UI应用程序( WPF / Winforms )使用SynchronizationContext ,它仅允许主( UI )线程与UI元素进行交互,因此它可以与async-await无缝async-await

ASP.Net also has it's own SynchronizationContext called AspNetSynchronizationContext (surprisingly). ASP.Net也有自己的SynchronizationContext称为AspNetSynchronizationContext (令人惊讶)。 So it isn't necessarily about UI or Single Thread Apartments . 因此,它不一定与UISingle Thread Apartments有关


If you want to disable that useful SynchronizationContext capturing you just need to use ConfigureAwait : 如果要禁用有用的SynchronizationContext捕获,则只需使用ConfigureAwait

await Task.Run(() =>
{
    Thread.CurrentThread.Name = "child";
    Thread.Sleep(5000);
}).ConfigureAwait(false);

More on SynchronizationContexts: It's All About the SynchronizationContext 有关SynchronizationContext的更多信息: 一切都与SynchronizationContext有关

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM