c# - example - espera múltiple frente a Task.WaitAll-¿equivalente?
task waitall example c# (4)
La primera opción no ejecutará las dos operaciones al mismo tiempo. Ejecutará el primero y esperará su consumación, y solo entonces el segundo.
La segunda opción se ejecutará simultáneamente, pero las esperará de forma síncrona (es decir, mientras bloquea un hilo).
No debe usar ambas opciones ya que la primera completa más lentamente que la segunda y la segunda bloquea una secuencia sin necesidad.
Debe esperar ambas operaciones de forma asincrónica con Task.WhenAll
:
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);
customer.Widgets = await getAllWidgetsTask;
customer.Foos = await getAllFoosTask;
return Ok(customer);
}
Tenga en cuenta que después de Task.WhenAll
dos tareas ya completadas, Task.WhenAll
que se completen de inmediato.
En términos de rendimiento, ¿ejecutarán estos dos métodos GetAllWidgets()
y GetAllFoos()
en paralelo?
¿Hay alguna razón para usar una sobre la otra? Parece que suceden muchas cosas entre bastidores con el compilador, por lo que no me parece claro.
Metodología =======
public async Task<IHttpActionResult> MethodA()
{
var customer = new Customer();
customer.Widgets = await _widgetService.GetAllWidgets();
customer.Foos = await _fooService.GetAllFoos();
return Ok(customer);
}
================================================= Metodulo B
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
Task.WaitAll(new List[] {getAllWidgetsTask, getAllFoosTask});
customer.Widgets = getAllWidgetsTask.Result;
customer.Foos = getAllFoosTask.Result;
return Ok(customer);
}
==================================
Respuesta corta: No.
Task.WaitAll
is blocking, Task.WaitAll
devuelve la tarea tan pronto como se encuentra y registra la parte restante de la función y la continuación.
El método de espera "masivo" que estaba buscando es Task.WhenAll
eso crea una Task
nueva que termina cuando se realizan todas las tareas que se entregaron a la función.
De esta manera: await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});
Eso es para el asunto de bloqueo.
Además, su primera función no ejecuta ambas funciones en paralelo. Para que funcione esto con await
deberías escribir algo como esto:
var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;
Esto hará que el primer ejemplo sea muy similar al método Task.WhenAll
.
Solo su segunda opción los ejecutará en paralelo. El primero esperará en cada llamada en secuencia.
Tan pronto como invoque el método async, comenzará a ejecutarse. No se podrá determinar si se ejecutará en el hilo actual (y por lo tanto se ejecutará de forma síncrona) o se ejecutará de forma asíncrona.
Por lo tanto, en su primer ejemplo, el primer método comenzará a funcionar, pero luego detiene artificialmente el flujo del código con la espera. Y así el segundo método no se invocará antes de que el primero se termine de ejecutar.
El segundo ejemplo invoca ambos métodos sin detener el flujo con una espera. Por lo tanto, potencialmente se ejecutarán en paralelo si los métodos son asincrónicos.