试着了解何时应该使用ConfigureAwait()。 根据书:
When an async method resumes after an await, by default it will resume executing within the same context. This can cause performance problems if that context was a UI context and a large number of async methods are resuming on the UI context.
Solution
To avoid resuming on a context, await the result of ConfigureAwait and pass false
for its continueOnCapturedContext parameter:
async Task ResumeWithoutContextAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
// This method discards its context when it resumes.
}
什么是上下文以及如何查看ConfigureAwait()更改示例应用程序中的内容:
static async Task ResumeWithoutContextAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(true);
Console.WriteLine("ManagedThreadId {0}", Thread.CurrentThread.ManagedThreadId);
// This method discards its context when it resumes.
}
static void Main(string[] args)
{
ResumeWithoutContextAsync();
Console.ReadLine();
}
我认为上下文是Thread,但事实并非如此。
答案 0 :(得分:3)
这里的上下文是SynchronizationContext
。如果它存在并且你没有使用SynchronizationContext.Current
false,Await会将continuation(等待之后的方法的其余部分)发布到当前上下文(ConfigureAwait
)。如果未将continuation发布到上下文 - 它将在线程池线程上执行。在控制台应用程序中,默认情况下没有同步上下文,因此在您的测试中ConfigureAwait
无效。您可以创建虚拟上下文来查看效果:
class MySynchornizationContext : SynchronizationContext {
public override void Post(SendOrPostCallback d, object state) {
Console.WriteLine("posted");
base.Post(d, state);
}
public override void Send(SendOrPostCallback d, object state) {
Console.WriteLine("sent");
base.Send(d, state);
}
}
然后在Main
方法的开头:
SynchronizationContext.SetSynchronizationContext(new MySynchornizationContext());
使用ConfigureAwait(true)
(或根本没有) - 您将看到延续已发布到上下文(控制台中的“已发布”行)。使用ConfigureAwait(false)
- 您将看到它不是。
实际同步上下文比当然更复杂。例如,UI上下文(如在winforms或WPF中)将“排队”延续并在一个(UI)线程上执行它们。由于各种原因(并且可能导致死锁),这可能会引起问题,因此当您编写通用库时 - 使用ConfigureAwait(false
来避免此行为是有益的。
SynchronizationContext
不需要将所有回调发布到单个线程,它可以对它们执行任何操作。例如,ASP.NET MVC上下文(至少是旧版本)会将回调发布到请求线程,并且可能有很多请求这么多请求线程。
答案 1 :(得分:-2)
今天,我们主要在通过REST调用访问的快速服务中编写JSON服务。本机GUI应用程序以及IIS Application Server要求异步任务在原始线程上下文上恢复执行。不幸的是,这种对上世纪发展的偏见迫使我们几乎在服务代码中的每个调用上都使用“ ConfigureAwait(false)”。
最后,这是一个非常令人困惑和误导的名称。它读作“做或不配置等待”,但实际上它是“线程亲缘性为真或假”。没有其他选项,因此它不是一般的配置方法。