En el siguiente código, quiero sincronizar el informe de los resultados de una lista de tareas. Esto funciona ahora porque task.Result bloquea hasta que la tarea se complete. Sin embargo, la tarea id = 3 tarda mucho tiempo en completarse y bloquea todas las demás tareas terminadas al informar su estado.Sincronización de tarea sin un subproceso UI
Creo que puedo hacer esto moviendo los informes (Console.Write) a una instrucción .ContinueWith pero no tengo un subproceso de interfaz de usuario así que ¿cómo obtengo un TaskScheduler para sincronizar las tareas .ContinueWith?
Lo que tengo ahora:
static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
var tasks = new List<Task<int>>();
for (var i = 0; i < 10; i++)
{
var num = i;
var t = Task<int>.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 5000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
return num;
});
tasks.Add(t);
}
foreach (var task in tasks)
{
Console.WriteLine("Completed {0} on {1}", task.Result, Thread.CurrentThread.ManagedThreadId);
}
Console.WriteLine("End of Main");
Console.ReadKey();
}
me gustaría pasar a esto o algo similar, pero necesito el Console.Write ("Completado ...") a todo suceda en el mismo subproceso:
static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
for (var i = 0; i < 10; i++)
{
var num = i;
Task<int>.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 10000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
return num;
}).ContinueWith(value =>
{
Console.WriteLine("Completed {0} on {1}", value.Result, Thread.CurrentThread.ManagedThreadId);
}
/* need syncronization context */);
}
Console.WriteLine("End of Main");
Console.ReadKey();
}
- sOLUCIÓN - Después de conseguir algunos comentarios y leer algunas de las soluciones es la solución completa que hace lo que yo quiero. El objetivo aquí es procesar las tareas de larga ejecución de manera tan rápida como sea posible y luego hacer algo con los resultados de cada tarea de a una por vez.
static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
var results = new BlockingCollection<int>();
Task.Factory.StartNew(() =>
{
while (!results.IsCompleted)
{
try
{
var x = results.Take();
Console.WriteLine("Completed {0} on {1}", x, Thread.CurrentThread.ManagedThreadId);
}
catch (InvalidOperationException)
{
}
}
Console.WriteLine("\r\nNo more items to take.");
});
var tasks = new List<Task>();
for (var i = 0; i < 10; i++)
{
var num = i;
var t = Task.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 10000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
results.Add(num);
});
tasks.Add(t);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(), _ => results.CompleteAdding());
Console.WriteLine("End of Main");
Console.ReadKey();
}
que asumen el hilo de la consola es un sustituto de una interfaz gráfica de usuario (Windows Forms/WPF). Lo cual no es una buena idea, la presencia de un Dispatcher/Messageloop marca una (gran) diferencia. –
De lo contrario, piense en lo que quiere decir con "pasar en el mismo hilo". No se puede hacer eso a menos que ese hilo sea un sondeo. –
Necesito cambiarlo para que solo una de las tareas ContinueWith se ejecute a la vez. No importa si se ejecutan en el mismo hilo o no, pero no puedo tener dos corriendo en paralelo. En la vida real, la parte ContinueWith está escribiendo una gran cantidad de datos en una base de datos. –