Eu tenho a seguinte operação em uma API Web que criei:
// GET api/<controller>
[HttpGet]
[Route("pharmacies/{pharmacyId}/page/{page}/{filter?}")]
public CartTotalsDTO GetProductsWithHistory(Guid pharmacyId, int page, string filter = null ,[FromUri] bool refresh = false)
{
return delegateHelper.GetProductsWithHistory(CustomerContext.Current.GetContactById(pharmacyId), refresh);
}
A chamada para este serviço da web é feita por meio de uma chamada Jquery Ajax desta forma:
$.ajax({
url: "/api/products/pharmacies/<%# Farmacia.PrimaryKeyId.Value.ToString() %>/page/" + vm.currentPage() + "/" + filter,
type: "GET",
dataType: "json",
success: function (result) {
vm.items([]);
var data = result.Products;
vm.totalUnits(result.TotalUnits);
}
});
Já vi alguns desenvolvedores que implementam a operação anterior desta forma:
// GET api/<controller>
[HttpGet]
[Route("pharmacies/{pharmacyId}/page/{page}/{filter?}")]
public async Task<CartTotalsDTO> GetProductsWithHistory(Guid pharmacyId, int page, string filter = null ,[FromUri] bool refresh = false)
{
return await Task.Factory.StartNew(() => delegateHelper.GetProductsWithHistory(CustomerContext.Current.GetContactById(pharmacyId), refresh));
}
Devo dizer, porém, que GetProductsWithHistory () é uma operação bastante longa. Dado o meu problema e contexto, como tornar a operação webAPI assíncrona me beneficiará?
c#
jquery
ajax
asp.net-web-api
async-await
David Jiménez Martínez
fonte
fonte
async Task<T>
. Lembre-se, AJAX foi implementado antes mesmo de o TPL existir :)GetProductsWithHistoryAsync()
devolvidoTask<CartTotalsDTO>
. Pode haver uma vantagem em gravar seu controlador de forma assíncrona se você pretende migrar as chamadas que ele faz para serem assíncronas também; então você começa a tirar proveito das partes assíncronas conforme migra o resto.Respostas:
Em seu exemplo específico, a operação não é assíncrona, então o que você está fazendo é assíncrono durante a sincronização. Você está apenas liberando um tópico e bloqueando outro. Não há razão para isso, porque todos os threads são threads de pool de threads (ao contrário de um aplicativo GUI).
De Devo expor wrappers síncronos para métodos assíncronos?
No entanto, ao fazer chamadas WebAPI
async
onde há uma operação assíncrona real (geralmente E / S) em vez de bloquear um thread que fica e espera por um resultado, o thread volta para o pool de threads e, portanto, é capaz de realizar alguma outra operação. Acima de tudo, isso significa que seu aplicativo pode fazer mais com menos recursos e isso melhora a escalabilidade.fonte
await Task.Run(() => CPUIntensive())
) é inútil no asp.net. Você não ganha nada fazendo isso. Você está apenas liberando um thread ThreadPool para ocupar outro. É menos eficiente do que simplesmente chamar o método síncrono.await Task.WhenAll
para executar em paralelo.Task.Run
se quiser paralelizar sua carga em vários threads, mas não é isso que "async over sync" significa. "async over sync" faz referência à criação de um método assíncrono como um wrapper sobre um síncrono. Você pode ver na citação da minha resposta.Uma abordagem poderia ser (eu usei isso com sucesso em aplicativos de cliente) ter um serviço do Windows executando as operações demoradas com threads de trabalho e, em seguida, fazer isso no IIS para liberar os threads até que a operação de bloqueio seja concluída: Observe, isso pressupõe os resultados são armazenados em uma tabela (linhas identificadas por jobId) e um processo mais limpo limpando-os algumas horas após o uso.
Para responder à pergunta, "Dado meu problema e contexto, como tornar a operação assíncrona da webAPI me beneficiará?" considerando que é "uma operação bastante longa", estou pensando em muitos segundos em vez de ms, essa abordagem libera threads do IIS. Obviamente, você também deve executar um serviço do Windows que consome recursos, mas essa abordagem pode evitar que uma inundação de consultas lentas roube threads de outras partes do sistema.
fonte