Estoy usando un cliente API que es completamente asíncrono, es decir, cada operación devuelve Tasko Task<T>, por ejemplo:
static async Task DoSomething(int siteId, int postId, IBlogClient client)
{
await client.DeletePost(siteId, postId); // call API client
Console.WriteLine("Deleted post {0}.", siteId);
}
Usando los operadores asíncronos / en espera de C # 5, ¿cuál es la forma correcta / más eficiente de iniciar múltiples tareas y esperar a que todas se completen?
int[] ids = new[] { 1, 2, 3, 4, 5 };
Parallel.ForEach(ids, i => DoSomething(1, i, blogClient).Wait());
o:
int[] ids = new[] { 1, 2, 3, 4, 5 };
Task.WaitAll(ids.Select(i => DoSomething(1, i, blogClient)).ToArray());
Dado que el cliente API está utilizando HttpClient internamente, esperaría que esto emita 5 solicitudes HTTP de inmediato, escribiendo en la consola a medida que se completa cada una.
c#
.net
task-parallel-library
async-await
c#-5.0
Ben Foster
fuente
fuente

Respuestas:
Aunque ejecuta las operaciones en paralelo con el código anterior, este código bloquea cada subproceso en el que se ejecuta cada operación. Por ejemplo, si la llamada de red tarda 2 segundos, cada subproceso se cuelga durante 2 segundos sin hacer nada más que esperar.
Por otro lado, el código anterior
WaitAlltambién bloquea los hilos y sus hilos no serán libres de procesar ningún otro trabajo hasta que finalice la operación.Enfoque recomendado
Prefiero
WhenAllque realice sus operaciones de forma asincrónica en paralelo.Para respaldar esto, aquí hay una publicación de blog detallada que detalla todas las alternativas y sus ventajas / desventajas: Cómo y dónde E / S asincrónicas concurrentes con API web ASP.NET
fuente
WaitAlltambién bloquea los hilos" - ¿no bloquea solo un hilo, el que llamóWaitAll?Tenía curiosidad por ver los resultados de los métodos proporcionados en la pregunta, así como la respuesta aceptada, así que lo puse a prueba.
Aquí está el código:
Y el resultado resultante:
fuente
Como la API a la que llama es asíncrona, la
Parallel.ForEachversión no tiene mucho sentido. No debe usar.Waiten laWaitAllversión ya que eso perdería el paralelismo. Otra alternativa si la persona que llama es asíncrona está usandoTask.WhenAlldespués de hacerSelectyToArraygenerar la matriz de tareas. Una segunda alternativa es usar Rx 2.0fuente
Puede usar la
Task.WhenAllfunción que puede pasar n tareas;Task.WhenAlldevolverá una tarea que se ejecutará hasta completar cuando se completen todas las tareas que pasóTask.WhenAll. Tienes que esperar asincrónicamenteTask.WhenAllpara que no bloquees tu hilo de la interfaz de usuario:fuente
Parallel.ForEachrequiere una lista de trabajadores definidos por el usuario y una no asíncronaActionpara realizar con cada trabajador.Task.WaitAllyTask.WhenAllrequieren unList<Task>, que son por definición asíncronos.La respuesta de RiaanDP me pareció muy útil para entender la diferencia, pero necesita una corrección . No hay suficiente reputación para responder a su comentario, de ahí mi propia respuesta.
Parallel.ForEachLa salida resultante está debajo. Los tiempos de ejecución son comparables. Ejecuté esta prueba mientras mi computadora realizaba el análisis antivirus semanal. Cambiar el orden de las pruebas cambió los tiempos de ejecución en ellas.
fuente