ConfigureAwait()
只影响延续操作,所以你调用
OnTheBackground()
的时候是从调用线程的上下文中调用 - 此时不会创建新线程。
在等待
OnTheBackground()
后完成后,延续操作可能在新线程上运行 - 但如果
OnTheBackground()
中没有任何阻塞操作,则仍可能在调用线程上继续。因此,在异步方法中进行计算密集型操作需要小心!
以下是一个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);
}
当您首次单击该按钮时,它将在
OnTheBackground()
内调用
await Task.Delay(0)
。因为这不需要阻塞,所以当
await Task.Delay(0)
返回时,它会继续在调用它的同一个线程上运行。
然后,当它返回到
Button_Click()
时,即使其中的await带有
.ConfigureAwait(false)
,它也将继续在原始UI线程上运行,因为它调用的任何内容都没有转换到不同的线程。
因此,在第一次按下按钮时,调试窗口中的输出大致如下:
Button_Click() called on thread 1
OnTheBackground() called on thread 1
OnTheBackground() continued on thread 1
Button_Click() continued on thread 1
一切都在同一个线程上,这是预期的。
然而,在第二次按下按钮时,它最终会调用await Task.Delay(10);
,这将导致等待在一个新线程上返回,因为Task.Delay(10)
将被阻塞。
因此,当它回到await OnTheBackground().ConfigureAwait(false);
时,它将不会继续在UI线程上进行,而是继续在另一个线程上进行。
因此,在第二次按下按钮时,调试输出类似于:
Button_Click() called on thread 1
OnTheBackground() called on thread 1
OnTheBackground() continued on thread 1
Button_Click() continued on thread 4
在这种情况下,您可以看到在
Button_Click()
中
await
之后的代码现在正在非UI线程上运行。
ConfigureAwait()
只影响继续执行,因此您对OnTheBackground()
的调用是从调用线程的上下文中调用的 - 此时不会创建新线程。在等待OnTheBackground()
完成后,继续执行可能在新线程上 - 但如果OnTheBackground()
中没有阻塞任何内容,则仍可能在调用线程上继续执行。因此,即使在async
方法中,您也必须小心处理计算密集型任务。 - Matthew Watsonawait someClient.Execute();
使用套接字(因此使用IOCP),并且内部套接字缓冲区中没有任何内容,因此它无法直接完成。如果我理解你的意思正确,那么由于在SomeMouseClick
中没有继续执行,并且对someClient.Execute
的调用没有配置继续执行的位置,所以OnTheBackground
调用将在UI线程上继续执行? - jgauffinDebug.WriteLine(Thread.CurrentThread.ManagedThreadId);
来检查这一点,以查看线程运行情况。请注意,在SomeMouseClick()
中等待OnTheBackground()
完成后,它将在不同的线程上运行(假设await someClient.Execute();
在不同的线程上恢复)。 - Matthew Watson