c# programación - Ejecutar varias tareas asíncronas y esperar a que se completen todas




mismo al (6)

Necesito ejecutar varias tareas asíncronas en una aplicación de consola y esperar a que se completen todas antes de continuar el proceso.

Hay muchos artículos por ahí, pero parece que estoy más confundido cuanto más leo. He leído y entiendo los principios básicos de la biblioteca de tareas, pero claramente me falta un enlace en alguna parte.

Entiendo que es posible encadenar tareas para que comiencen después de que se complete otra (que es prácticamente el escenario para todos los artículos que he leído), pero quiero que todas mis tareas se ejecuten al mismo tiempo, y quiero saber una vez todos están completos.

¿Cuál es la implementación más simple para un escenario como este?


Answers

Podrías crear muchas tareas como:

List<Task> TaskList = new List<Task>();
foreach(...)
{
   var LastTask = new Task(SomeFunction);
   LastTask.Start();
   TaskList.Add(LastTask);
}

Task.WaitAll(TaskList.ToArray());

Así es como lo hago con una matriz Func <> :

var tasks = new Func<Task>[]
{
   () => myAsyncWork1(),
   () => myAsyncWork2(),
   () => myAsyncWork3()
};

await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async    
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync

Puede usar WhenAll que devolverá una Task o WaitAll que no tenga ningún tipo de retorno y bloqueará la ejecución de código simular a Thread.Sleep hasta que todas las tareas se completen, cancelen o fallen.

Ejemplo

var tasks = new Task[] {
    await TaskOperationOne(),
    await TaskOperationTwo()
};

Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);

Si desea ejecutar las tareas en un orden particular, puede obtener inspiración de this manual.


La mejor opción que he visto es el siguiente método de extensión:

public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) {
    return Task.WhenAll(sequence.Select(action));
}

Llámalo así:

await sequence.ForEachAsync(item => item.SomethingAsync(blah));

O con una lambda asíncrona:

await sequence.ForEachAsync(async item => {
    var more = await GetMoreAsync(item);
    await more.FrobbleAsync();
});

¿Desea encadenar las Task , o pueden invocarse de forma paralela?

Para encadenar
Solo haz algo como

Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);

y no olvide verificar la instancia de la Task anterior en cada ContinueWith ya que podría tener una falla.

Para la forma paralela
El método más simple que encontré: Parallel.Invoke De lo contrario, hay Task.WaitAll o incluso puedes usar WaitHandle s para hacer una cuenta atrás para poner en cero las acciones restantes (espera, hay una nueva clase: CountdownEvent ), o ...


Vea un ejemplo sobre cómo puede hacer esto con el código fuente completo aquí:

http://www.csharphelp.com/2006/08/get-current-window-handle-and-caption-with-windows-api-in-c/

[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

private string GetActiveWindowTitle()
{
    const int nChars = 256;
    StringBuilder Buff = new StringBuilder(nChars);
    IntPtr handle = GetForegroundWindow();

    if (GetWindowText(handle, Buff, nChars) > 0)
    {
        return Buff.ToString();
    }
    return null;
}

Editado con comentarios de @Doug McClean para una mejor corrección.





c# .net asynchronous task-parallel-library async-await