试图了解何时应使用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();
}
我当时以为上下文是线程,但事实并非如此。
最佳答案
这里的上下文是SynchronizationContext
。如果存在,并且您未使用SynchronizationContext.Current
false,则Await会将延续(在等待之后的方法的其余部分)发布到当前上下文(ConfigureAwait
)。如果继续未发布到上下文-它将在线程池线程上执行。在控制台应用程序中,默认情况下没有同步上下文,因此在您的测试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)
(或完全不使用)-您将看到延续已发布到上下文(控制台中的“ posted”行)。使用ConfigureAwait(false)
-您会看到不是。实际的同步上下文比当然要复杂得多。例如,UI上下文(例如在Winforms或WPF中)将“排队”延续并在一个(UI)线程上执行它们。如您的问题引文中所述,这可能是有问题的,由于各种原因(并可能导致死锁),因此在编写通用库时,使用
ConfigureAwait(false
避免这种行为是有益的。当然,不需要
SynchronizationContext
将所有回调都发布到单个线程中,它可以对它们执行任何操作。例如,ASP.NET MVC上下文(至少是旧版本)将回调发送到请求线程,并且可能有很多请求,所以请求线程很多。关于c# - 了解ConfigureAwait,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47217849/