[C#] Usando async / await para múltiples tareas


Answers

Tenía curiosidad de 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:

class Program
{
    class Worker
    {
        public int Id { get; set; }
        public int SleepTimeout { get; set; }

        public async Task DoWork()
        {
            Console.WriteLine("Worker {0} started on thread {1} at {2}.",
                Id, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("hh:mm:ss.fff"));
            await Task.Run(() => Thread.Sleep(SleepTimeout));
            Console.WriteLine("Worker {0} stopped at {1}.",
                Id, DateTime.Now.ToString("hh:mm:ss.fff"));
        }
    }

    static void Main(string[] args)
    {
        var workers = new List<Worker>
        {
            new Worker { Id = 1, SleepTimeout = 3000 },
            new Worker { Id = 2, SleepTimeout = 3000 },
            new Worker { Id = 3, SleepTimeout = 3000 },
            new Worker { Id = 4, SleepTimeout = 3000 },
            new Worker { Id = 5, SleepTimeout = 3000 },
        };

        Console.WriteLine("Starting test: Parallel.ForEach");
        PerformTest_ParallelForEach(workers);
        Console.WriteLine("Test finished.\n");

        Console.WriteLine("Starting test: Task.WaitAll");
        PerformTest_TaskWaitAll(workers);
        Console.WriteLine("Test finished.\n");

        Console.WriteLine("Starting test: Task.WhenAll");
        var task = PerformTest_TaskWhenAll(workers);
        task.Wait();
        Console.WriteLine("Test finished.\n");

        Console.ReadKey();
    }

    static void PerformTest_ParallelForEach(List<Worker> workers)
    {
        Parallel.ForEach(workers, worker => worker.DoWork().Wait());
    }

    static void PerformTest_TaskWaitAll(List<Worker> workers)
    {
        Task.WaitAll(workers.Select(worker => worker.DoWork()).ToArray());
    }

    static Task PerformTest_TaskWhenAll(List<Worker> workers)
    {
        return Task.WhenAll(workers.Select(worker => worker.DoWork()));
    }
}

Y el resultado resultante:

Question

Estoy usando un cliente API que es completamente asincrónico, es decir, cada operación devuelve Task o 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);
}

Al utilizar los operadores asíncrono / en espera C # 5, ¿cuál es la forma correcta / más eficiente de iniciar múltiples tareas y esperar a que se completen todas?

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());

Como el cliente API está utilizando HttpClient internamente, esperaría que se emitan 5 solicitudes HTTP de inmediato, escribiendo en la consola a medida que se completa.




Puede usar Task.WhenAll . Task.WhenAll funciones pueden pasar n tareas; Task.WhenAll devolverá una tarea que se ejecuta hasta su finalización cuando todas las tareas que pasó a Task.WhenAll complete. Tienes que esperar asíncronamente en Task.WhenAll para que no bloquees tu subproceso de UI:

   public async Task DoSomeThing() {

       var Task[] tasks = new Task[numTasks];
       for(int i = 0; i < numTask; i++)
       {
          tasks[i] = CallSomeAsync();
       }
       await Task.WhenAll(tasks);
       // code that'll execute on UI thread
   }