/ / Async demorando 15x mais que sync - c #, asp.net, asp.net-web-api, async-await, dotnet-httpclient

Assíncrono demorando 15x mais que sync - c #, asp.net, asp.net-web-api, async-await, dotnet-httpclient

Eu estou comparando o desempenho ao tirar await palavra-chave do meu método e está me dando um desempenho 15x melhor.

O método a seguir funciona muito melhor:

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;
}

que este:

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;
}

Observe como estou ligando .Resultado na primeira versão do método.

Por que isso está acontecendo? Por que há uma tremenda penalidade no desempenho?

Por favor note que Client é simplesmente uma instância estática de HttpClient.

Respostas:

4 para resposta № 1

Ao usar await, o contexto de execução do código é suspenso até que o método assíncrono seja retornado. Por padrão, await tenta restaurar o novo segmento para ocontexto de sincronização de entrada originado. Isso pode, às vezes, ter implicações de desempenho, já que o CLR precisa aguardar o SynchronizationContext original para retornar.

De um modo geral, a menos que você tenha uma necessidade específica de retornar ao mesmo contexto de encadeamento que você deixou (digamos, em um aplicativo cliente, para retornar ao encadeamento da interface do usuário), é melhor adicioná-lo ConfigureAwait(false) e continue em qualquer thread arbitrário.


4 para resposta № 2

Dado que você realmente não usa a resposta para nada nos trechos, não há necessidade de usar async / await ou chamar .Result. Você pode simplesmente devolver o Task para o chamador aguardar ou ligar .Result em um nível mais alto.

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);
}

Eu também sugiro rever

Async / Await - Melhores Práticas em Programação Assíncrona de Stephen Cleary

as questões em torno de não misturar o código de bloqueio e assíncrono e também sobre como e quando ConfigureAwait(false) quando você puder