c# - parallel - Use Task.WaitAll() para manejar las tareas esperadas?
task waitall c# (2)
Idealmente, lo que quiero hacer es retrasar una tarea con un modo de no bloqueo y luego esperar a que todas las tareas se completen. He intentado agregar el objeto de tarea devuelto por Task.Delay y luego usar Task.WaitAll pero parece que esto no ayudará. ¿Cómo debo resolver este problema?
class Program
{
public static async void Foo(int num)
{
Console.WriteLine("Thread {0} - Start {1}", Thread.CurrentThread.ManagedThreadId, num);
var newTask = Task.Delay(1000);
TaskList.Add(newTask);
await newTask;
Console.WriteLine("Thread {0} - End {1}", Thread.CurrentThread.ManagedThreadId, num);
}
public static List<Task> TaskList = new List<Task>();
public static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
int idx = i;
TaskList.Add(Task.Factory.StartNew(() => Foo(idx)));
}
Task.WaitAll(TaskList.ToArray());
}
}
¿Es esto lo que estás tratando de lograr?
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
public static async Task Foo(int num)
{
Console.WriteLine("Thread {0} - Start {1}", Thread.CurrentThread.ManagedThreadId, num);
await Task.Delay(1000);
Console.WriteLine("Thread {0} - End {1}", Thread.CurrentThread.ManagedThreadId, num);
}
public static List<Task> TaskList = new List<Task>();
public static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
int idx = i;
TaskList.Add(Foo(idx));
}
Task.WaitAll(TaskList.ToArray());
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
}
}
Salida:
Thread 10 - Start 0 Thread 10 - Start 1 Thread 10 - Start 2 Thread 6 - End 0 Thread 6 - End 2 Thread 6 - End 1 Press Enter to exit...
Lo que hay que tener en cuenta es que, como Foo es asíncrono, en sí mismo es una Tarea. Tu ejemplo tiene tareas que simplemente inician la tarea de Foo
, pero no esperes.
En otras palabras, Task.WaitAll(TaskList.ToArray())
simplemente está esperando que se Task.Delay
cada Task.Delay
, pero no está esperando que todas estas tareas terminen.
Esto podría ser lo que estás tratando de lograr:
class Program
{
public static async Task Foo(int num)
{
Console.WriteLine("Thread {0} - Start {1}", Thread.CurrentThread.ManagedThreadId, num);
var newTask = Task.Delay(1000);
await newTask;
Console.WriteLine("Thread {0} - End {1}", Thread.CurrentThread.ManagedThreadId, num);
}
public static List<Task> TaskList = new List<Task>();
public static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
int idx = i;
Task fooWrappedInTask = Task.Run(() => Foo(idx));
TaskList.Add(fooWrappedInTask);
}
Task.WaitAll(TaskList.ToArray());
Console.WriteLine("Finished waiting for all of the tasks: - Thread {0}", Thread.CurrentThread.ManagedThreadId);
}
}
He probado esto, y produce la salida de consola a la que apuntas.
La principal diferencia aquí es que estamos llamando aTask.Run
lugar de Task.Factory.StartNew
. Es posible que tenga una Task
que devuelva una Task
, que incluso podría devolver otra Task
. Pensarías en esto como una "cadena" de tareas.
Task.Run
devuelve una Task
que representa la tarea final en la cadena. Cuando lo espera, está esperando que se complete cada enlace en la cadena de tareas.
En comparación, Task.Factory.StartNew
devuelve una tarea que representa el primer enlace de la cadena. Después de haberlo esperado, quedará con el resto de la cadena por esperar. Esto está bien en la gran mayoría de los casos en que la Task
devuelve algo que no es otra Task
.