异步比同步花费 15 倍的时间

Async taking 15x longer than sync

我正在比较从我的方法中删除 await 关键字时的性能,它使我的性能提高了 15 倍以上。

下面的方法执行得更好:

private static async Task<HttpResponseMessage> AwaitResponse(HttpRequest proxy)
{
    foreach (var header in proxy.Request.Headers)
    {
        Client.Instance.DefaultRequestHeaders.Add(header.Key, header.Value);
    }

    var response = Client.Instance.SendAsync(proxy.Request).Result;
    return response;
}

比这个:

private static async Task<HttpResponseMessage> AwaitResponse(HttpRequest proxy)
{
    foreach (var header in proxy.Request.Headers)
    {
        Client.Instance.DefaultRequestHeaders.Add(header.Key, header.Value);
    }

    var response = Client.Instance.SendAsync(proxy.Request);
    return await response;
}

请注意我是如何在方法的第一个版本中调用 .Result 的。

为什么会这样?为什么会有如此巨大的性能损失?

请注意 Client 只是 HttpClient 的静态实例。

当使用await时,代码的执行上下文被挂起,直到异步方法returns。默认情况下,await 尝试将新线程恢复到它发起的传入同步上下文。这有时会影响性能,因为 CLR 需要等待原始 SynchronizationContext 编组回来。

一般来说,除非您有特定需要 return 到您离开的同一线程上下文(例如,在客户端应用程序中,return 到 UI 线程),最好添加 ConfigureAwait(false) 并在任意线程上继续。

鉴于您实际上并未对代码段中的任何内容使用响应,因此无需实际使用 async/await 或调用 .Result。您可以 return 呼叫者 Task 等待或在更高级别呼叫 .Result

private static Task<HttpResponseMessage> AwaitResponse(HttpRequest proxy) {
    foreach (var header in proxy.Request.Headers) {
        Client.Instance.DefaultRequestHeaders.Add(header.Key, header.Value);
    }
    return Client.Instance.SendAsync(proxy.Request);
}

我还建议查看

Async/Await - Best Practices in Asynchronous Programming 来自 Stephen Cleary

有关不混合阻塞代码和异步代码的问题,以及有关如何以及何时 ConfigureAwait(false) 可以

的问题