任务链(等待上一个任务完成)

时间:2012-07-25 12:23:24

标签: c# .net task-parallel-library task

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,我该如何做以下逻辑?

3 个答案:

答案 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());