Tengo un método en la aplicación ASP.NET, que consume bastante tiempo para completarse. Una llamada a este método puede ocurrir hasta 3 veces durante una solicitud de usuario, según el estado de la caché y los parámetros que proporciona el usuario. Cada llamada tarda entre 1 y 2 segundos en completarse. El método en sí es una llamada sincrónica al servicio y no hay posibilidad de anular la implementación.
Entonces, la llamada sincrónica al servicio se parece a lo siguiente:
public OutputModel Calculate(InputModel input)
{
// do some stuff
return Service.LongRunningCall(input);
}
Y el uso del método es (tenga en cuenta que la llamada al método puede ocurrir más de una vez):
private void MakeRequest()
{
// a lot of other stuff: preparing requests, sending/processing other requests, etc.
var myOutput = Calculate(myInput);
// stuff again
}
Traté de cambiar la implementación por mi parte para proporcionar un trabajo simultáneo de este método, y esto es lo que llegué hasta ahora.
public async Task<OutputModel> CalculateAsync(InputModel input)
{
return await Task.Run(() =>
{
return Calculate(input);
});
}
Uso (parte del código "hacer otras cosas" se ejecuta simultáneamente con la llamada al servicio):
private async Task MakeRequest()
{
// do some stuff
var task = CalculateAsync(myInput);
// do other stuff
var myOutput = await task;
// some more stuff
}
Mi pregunta es la siguiente. ¿Utilizo el enfoque correcto para acelerar la ejecución en la aplicación ASP.NET o estoy haciendo un trabajo innecesario al intentar ejecutar código síncrono de forma asincrónica? ¿Alguien puede explicar por qué el segundo enfoque no es una opción en ASP.NET (si realmente no lo es)? Además, si tal enfoque es aplicable, ¿debo llamar a dicho método de forma asincrónica si es la única llamada que podríamos realizar en este momento (tengo ese caso, cuando no hay otras cosas que hacer mientras espero que se complete)?
La mayoría de los artículos en la red sobre este tema cubren el uso de async-await
enfoque con el código, que ya proporciona awaitable
métodos, pero ese no es mi caso. aquíes el bonito artículo que describe mi caso, que no describe la situación de las llamadas paralelas, rechazando la opción de ajustar la llamada sincronizada, pero en mi opinión mi situación es exactamente la ocasión para hacerlo.
Gracias de antemano por la ayuda y los consejos.
fuente
Task.Run
, el contenido se ejecuta en otro hilo, que se toma del grupo de hilos. Entonces no hay ninguna necesidad de envolver las llamadas de bloqueo (como la llamada de la mina al servicio) enRun
s, porque siempre consumirán un hilo cada una, que se bloqueará durante la ejecución del método. En tal situación, el único beneficio que me quedaasync-await
en mi caso es realizar varias acciones a la vez. Por favor corrígeme si estoy equivocado.Run
(oParallel
) es la concurrencia. Las operaciones siguen bloqueando un hilo. Dado que dice que el servicio es un servicio web, no recomiendo usarRun
oParallel
; en su lugar, escriba una API asincrónica para el servicio.BeginGetResponse
y empezar a varias de las personas, y luego bloque (sincrónicamente) hasta que todos ellos están completos, pero este tipo de enfoque es difícil - ver blog.stephencleary.com/2012/07/dont-block-on -async-code.html y msdn.microsoft.com/en-us/magazine/mt238404.aspx . Por lo general, es más fácil y limpio de adoptar porasync
completo, si es posible.Descubrí que el siguiente código puede convertir una tarea para que siempre se ejecute de forma asincrónica
y lo he usado de la siguiente manera
Esto ejecutará cualquier tarea de forma asincrónica para que pueda combinarlas en escenarios WhenAll, WhenAny y otros usos.
También puede simplemente agregar Task.Yield () como la primera línea de su código llamado.
fuente