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);
}
这是UI线程的运行。我需要一个接一个地执行任务变量中的所有任务。问题是如果我调用Task.WaitAll(任务),UI冻结。如果不冻结UI,我该如何做以下逻辑?
答案 0 :(得分:27)
这不是任务链。
您需要使用ContinueWith
执行任务链接。上一个任务需要更新UI。
Task.Factory.StartNew( () => DoThis())
.ContinueWith((t1) => DoThat())
.ContinueWith((t2) => UpdateUi(),
TaskScheduler.FromCurrentSynchronizationContext());
注意最后一行有TaskScheduler.FromCurrentSynchronizationContext()
这将确保任务将在同步上下文(UI线程)中运行。
答案 1 :(得分:16)
最好的方法是使用任务并行库(TPL)和 Continuations 。延续不仅允许您创建任务流,还可以处理您的异常。这是TPL的great introduction。但是要给你一些想法......
您可以使用
启动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
'启动'并开始运行。请注意,如果task1
在到达第二行代码task2
之前已完成,则会安排立即执行。传递给第二个lambda的antTask
参数是对前一个任务的引用。有关详细示例,请参阅this link
您还可以传递先行任务的延续结果
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!") });
我希望这会有所帮助。
答案 2 :(得分:4)
您需要使用延续:
lastTask.ContinueWith(() => newTask.Start());