试图理解我什么时候应该使用ConfigureAwait()。
根据书:
当
async方法在等待之后恢复时,默认情况下它将在相同的上下文中继续执行。如果上下文是UI上下文,并且大量异步方法正在UI上下文上恢复,则这会导致性能问题。
解决方案
若要避免恢复上下文,请等待ConfigureAwait()的结果并为其continueOnCapturedContext参数传递false:
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,但事实并非如此。
发布于 2017-11-10 07:51:57
这里的上下文是SynchronizationContext。如果当前上下文(SynchronizationContext.Current)存在,并且没有使用ConfigureAwait false,Await将向当前上下文(等待后的方法的其余部分)发送延拓。如果继续没有提交到上下文-它将在线程池线程上执行。在控制台应用程序中,默认情况下不存在同步上下文,因此在您的测试中,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上下文(至少旧版本)会将回调发布到请求线程,并且可能会有很多请求,所以请求线程太多。
发布于 2018-10-25 17:59:34
今天,我们主要在通过REST调用访问的快速服务中编写JSON服务。本机GUI应用程序和IIS应用服务器还要求异步任务在原始线程上下文上恢复执行。不幸的是,对上个世纪开发的偏见迫使我们在服务代码中的几乎每一个调用上都使用"ConfigureAwait(false)“。
最后,这是一个令人困惑和误导的名字。它读为“做或不配置等待”,但实际上它是“线程亲和力真或假”。没有其他选项,所以它不是一般的配置方法。
https://stackoverflow.com/questions/47217849
复制相似问题