简体   繁体   English

在已经在线程池线程上运行的调用上配置等待?

[英]ConfigureAwait on a call which is already running on a threadpool thread?

I have a WPF application (and therefore a synchronization context).我有一个 WPF 应用程序(因此有一个同步上下文)。 In my async calls on the UI thread I use ConfigureAwait(false) to continue on a background thread.在 UI 线程上的异步调用中,我使用ConfigureAwait(false)在后台线程上继续。 That part I fully understand.那部分我完全理解。

However, once on a background thread, is ConfigureAwait(false) required for all following calls?但是,一旦在后台线程上,所有后续调用都需要ConfigureAwait(false)吗?

public async void SomeMouseClick(someArgs)
{
    await OnTheBackground().ConfigureAwait(false);
}

public async Task OnTheBackground()
{
    await someClient.Execute();
    // am I on the UI thread now, or on still on a thread pool thread?
}

The ConfigureAwait() only affects the continuation, so your call to OnTheBackground() is called from the context of the calling thread - a new thread is NOT created at that point. ConfigureAwait()仅影响延续,因此您对OnTheBackground()的调用是从调用线程的上下文中调用的 - 此时不会创建新线程。

After the await for OnTheBackground() completes, the continuation MAY be on a new thread - but if nothing in OnTheBackground() blocked it may still continue on the calling thread.在等待OnTheBackground()完成后,继续可能在一个新线程上 - 但如果OnTheBackground()没有任何阻塞,它可能仍会在调用线程上继续。 So you have to be careful about doing compute-bound stuff, even in an async method!所以你在做计算绑定的事情时必须小心,即使是在异步方法中!

This is best illustrated with an example.这最好用一个例子来说明。 Consider the following code for a WPF application with a single button called Button with its click event handled by a Button_Click() method:考虑以下 WPF 应用程序代码,该应用程序有一个名为Button ,其单击事件由Button_Click()方法处理:

bool firstTime = true;

private async void Button_Click(object sender, RoutedEventArgs e)
{
    Debug.WriteLine("Button_Click() called on thread " + Thread.CurrentThread.ManagedThreadId);

    await OnTheBackground().ConfigureAwait(false);

    Debug.WriteLine("Button_Click() continued on thread " + Thread.CurrentThread.ManagedThreadId);
}

public async Task OnTheBackground()
{
    Debug.WriteLine("OnTheBackground() called on thread " + Thread.CurrentThread.ManagedThreadId);

    if (firstTime)
        await Task.Delay(0);
    else
        await Task.Delay(10);

    firstTime = false;

    Debug.WriteLine("OnTheBackground() continued on thread " + Thread.CurrentThread.ManagedThreadId);
}

When you click the button the first time, it will wind up calling await Task.Delay(0);当你第一次点击按钮时,它会调用await Task.Delay(0); inside OnTheBackground() .OnTheBackground()里面。 Because this does not need to block, when the await Task.Delay(0) returns, it continues on the same thread that called it.因为这不需要阻塞,所以当await Task.Delay(0)返回时,它会在调用它的同一个线程上继续运行。

Then when this returns to Button_Click() , even though the await in there has .ConfigureAwait(false) it will continue on the original UI thread, because nothing that it called has transitioned to a different thread.然后,当它返回到Button_Click() ,即使那里的 await 具有.ConfigureAwait(false)它也会在原始 UI 线程上继续,因为它调用的任何内容都没有转换到不同的线程。

Thus, on first press of the button the output in the debug window is something like:因此,在第一次按下按钮时,调试窗口中的输出类似于:

Button_Click() called on thread 1
OnTheBackground() called on thread 1
OnTheBackground() continued on thread 1
Button_Click() continued on thread 1

Everything is on the same thread, as expected.正如预期的那样,一切都在同一个线程上。

However, on second press of the button it ends up calling await Task.Delay(10);但是,在第二次按下按钮时,它最终会调用await Task.Delay(10); which will cause the await to return on a new thread, since Task.Delay(10) will block.导致等待在新线程上返回,因为Task.Delay(10)将阻塞。

So when it gets back to await OnTheBackground().ConfigureAwait(false);所以当它回到await OnTheBackground().ConfigureAwait(false); , it will NOT continue on the UI thread, but rather continues on a different thread. ,它不会在 UI 线程上继续,而是在不同的线程上继续。

Thus on the second press of the button, the debug output is something like:因此,在第二次按下按钮时,调试输出类似于:

Button_Click() called on thread 1
OnTheBackground() called on thread 1
OnTheBackground() continued on thread 1
Button_Click() continued on thread 4

In this case, you can see that the code after the await in Button_Click() is now running on a non-UI thread.在这种情况下,您可以看到Button_Click() await之后的代码现在正在非 UI 线程上运行。

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

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