Целевая цепочка (дождитесь завершения предыдущей задачи)
var tasks = new List<Task>();
foreach (var guid in guids)
{
var task = new Task( ...);
tasks.Add(task);
}
foreach (var task in tasks)
{
task.Start();
Task.WaitAll(task);
}
Выполняется поток пользовательского интерфейса. Мне нужно выполнить все задачи в переменных задач один за другим. Проблема в том, что я вызываю Task.WaitAll(задачу), замораживание пользовательского интерфейса. Как я могу выполнить следующую логику без зависания пользовательского интерфейса?
Ответы
Ответ 1
Это не цепочка задач.
Вам нужно выполнить цепочку задач с помощью ContinueWith
. Последняя задача должна обновить пользовательский интерфейс.
Task.Factory.StartNew( () => DoThis())
.ContinueWith((t1) => DoThat())
.ContinueWith((t2) => UpdateUi(),
TaskScheduler.FromCurrentSynchronizationContext());
Примечание Последняя строка имеет TaskScheduler.FromCurrentSynchronizationContext()
, это обеспечит выполнение задачи в контексте синхронизации (поток пользовательского интерфейса).
Ответ 2
Лучший способ - использовать параллельную библиотеку задач (TPL) и Continuations. Продолжение не только позволяет вам создавать поток задач, но и обрабатывать ваши исключения. Это отличное введение в TPL. Но чтобы дать вам некоторую идею...
Вы можете запустить задачу TPL, используя
Task task = Task.Factory.StartNew(() =>
{
// Do some work here...
});
Теперь, чтобы запустить вторую задачу при завершении предшествующей задачи (по ошибке или успешно), вы можете использовать метод ContinueWith
Task task1 = Task.Factory.StartNew(() => Console.WriteLine("Antecedant Task"));
Task task2 = task1.ContinueWith(antTask => Console.WriteLine("Continuation..."));
Итак, как только task1
завершается, сбой или отменяется task2
'fires-up' и запускается. Обратите внимание, что если task1
завершилось до того, как вторая строка кода task2
была запланирована для немедленного выполнения. Аргумент antTask
, переданный во вторую лямбду, является ссылкой на предшествующую задачу. См. эту ссылку для более подробных примеров...
Вы также можете передавать результаты продолжения антецедентной задачи
Task.Factory.StartNew<int>(() => 1)
.ContinueWith(antTask => antTask.Result * 4)
.ContinueWith(antTask => antTask.Result * 4)
.ContinueWith(antTask =>Console.WriteLine(antTask.Result * 4)); // Prints 64.
Примечание. Обязательно ознакомьтесь с обработкой исключений в первой ссылке, поскольку это может привести к тому, что новичок в TPL спустится.
Последнее, что нужно посмотреть, в частности, на то, что вы хотите, - это детские задачи. Ребенок - это те, которые создаются как AttachedToParent
. В этом случае продолжение не будет выполняться до завершения всех дочерних задач
TaskCreationOptions atp = TaskCreationOptions.AttachedToParent;
Task.Factory.StartNew(() =>
{
Task.Factory.StartNew(() => { SomeMethod() }, atp);
Task.Factory.StartNew(() => { SomeOtherMethod() }, atp);
}).ContinueWith( cont => { Console.WriteLine("Finished!") });
Надеюсь, это поможет.
Ответ 3
Вам нужно использовать континуции:
lastTask.ContinueWith(() => newTask.Start());