Tengo la siguiente operación en una API web que creé:
// 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);
}
La llamada a este servicio web se realiza a través de una llamada Jquery Ajax de esta manera:
$.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);
}
});
He visto algunos desarrolladores que implementan la operación anterior de esta manera:
// 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));
}
Sin embargo, debo decir que GetProductsWithHistory () es una operación bastante larga. Dado mi problema y contexto, ¿cómo me beneficiará hacer que la operación webAPI sea asincrónica?
c#
jquery
ajax
asp.net-web-api
async-await
David Jiménez Martínez
fuente
fuente
async Task<T>
. Recuerde, AJAX se implementó antes de que existiera el TPL :)GetProductsWithHistoryAsync()
devoluciónTask<CartTotalsDTO>
. Puede ser beneficioso escribir su controlador asíncrono si tiene la intención de migrar las llamadas que realiza para que también sean asíncronas; luego comienza a beneficiarse de las partes asincrónicas a medida que migra el resto.Respuestas:
En su ejemplo específico, la operación no es asincrónica en absoluto, por lo que lo que está haciendo es asíncrona sobre sincronización. Solo estás liberando un hilo y bloqueando otro. No hay ninguna razón para eso, porque todos los subprocesos son subprocesos de grupo de subprocesos (a diferencia de una aplicación GUI).
Desde En caso expongo envoltorios síncronos de métodos asincrónicos?
Sin embargo, al realizar llamadas WebAPI
async
donde hay una operación asincrónica real (generalmente E / S) en lugar de bloquear un subproceso que se encuentra y espera un resultado, el subproceso vuelve al grupo de subprocesos y, por lo tanto, puede realizar alguna otra operación. Sobre todo, eso significa que su aplicación puede hacer más con menos recursos y eso mejora la escalabilidad.fuente
await Task.Run(() => CPUIntensive())
) es inútil en asp.net. No ganas nada al hacer eso. Solo está liberando un hilo ThreadPool para ocupar otro. Es menos eficiente que simplemente llamar al método sincrónico.await Task.WhenAll
para ejecutar en paralelo.Task.Run
si desea paralelizar su carga en varios subprocesos, pero eso no es lo que significa "async over sync". "async over sync" hace referencia a la creación de un método asincrónico como un contenedor sobre uno sincrónico. Puede ver el en la cita en mi respuesta.Un enfoque podría ser (he usado esto con éxito en aplicaciones de clientes) para que un servicio de Windows ejecute las operaciones largas con subprocesos de trabajo, y luego hacer esto en IIS para liberar los subprocesos hasta que se complete la operación de bloqueo: Tenga en cuenta, esto supone Los resultados se almacenan en una tabla (filas identificadas por jobId) y un proceso más limpio los limpia algunas horas después de su uso.
Para responder a la pregunta, "Dado mi problema y contexto, ¿cómo me beneficiará hacer que la operación webAPI sea asincrónica?" Dado que es "una operación bastante larga", creo que muchos segundos en lugar de ms, este enfoque libera subprocesos de IIS. Obviamente, también debe ejecutar un servicio de Windows que a su vez consume recursos, pero este enfoque podría evitar que una avalancha de consultas lentas robe hilos de otras partes del sistema.
fuente