.NET Framework 4.0:在循环中链接任务

5
我希望将多个Task链接起来,这样一个任务结束后下一个任务就开始。我知道可以使用ContinueWith完成此操作。但如果有大量任务,如下所示:

t1 继续执行 t2

t2 继续执行 t3

t3 继续执行 t4

...

有没有一种简便的方法,而不是手动使用循环创建此链?


2
你能否发布一下展示如何使用ContinueWith的代码?这可能会引发更多的反馈。 - RQDQ
2个回答

7

假设您有一些Action代理的可枚举列表,或者您想要执行某些操作,您可以轻松使用LINQ来执行以下操作:

// Create the base task.  Run synchronously.
var task = new Task(() => { });
task.RunSynchronously();

// Chain them all together.
var query = 
    // For each action
    from action in actions

    // Assign the task to the continuation and
    // return that.
    select (task = task.ContinueWith(action));

// Get the last task to wait on.
// Note that this cannot be changed to "Last"
// because the actions enumeration could have no
// elements, meaning that Last would throw.
// That means task can be null, so a check
// would have to be performed on it before
// waiting on it (unless you are assured that
// there are items in the action enumeration).
task = query.LastOrDefault();

上面的代码实际上是一个循环,只不过是以更高级的形式呈现。它完成了相同的任务,即采用先前的任务(在使用虚拟的“noop”Task进行初始化后),然后通过ContinueWith添加一个继续项(在此过程中将继续项分配给当前任务以进行下一次循环迭代,这是在调用LastOrDefault时执行的)。

3

您可以在这里使用静态扩展ContinueWhenAll

这样您就可以传递多个任务。


更新

您可以使用此类链接扩展:

public static class MyTaskExtensions
{
    public static Task BuildChain(this Task task, 
        IEnumerable<Action<Task>> actions)
    {
        if (!actions.Any())
            return task;
        else
        {
            Task continueWith = task.ContinueWith(actions.First());
            return continueWith.BuildChain(actions.Skip(1));
        }
    }
}

@Aliostad:我认为那不是答案,因为它们都依赖于前一个任务的完成(t3 依赖于 t2,t2 依赖于 t1,以此类推)。 - casperOne
是的,但我想你可以批量处理任务,每个批次一个。 - Aliostad
@Aliostad:这没有意义;每个前面的任务都有明确的依赖关系,等待所有任务完成后再继续会产生完全不同的效果。 - casperOne
1
@Aliostad:我已经调整了您的代码以提高可读性,但我还将行if (actions.Count() == 0)更改为if (!actions.Any()),因为Count() == 0(或Count()!= 0)是一个不好的想法 - casperOne
@Aliostad:上面的代码还有一个问题。每次递归迭代时,您都会传递actions.Skip(1)。这会导致枚举每次都从开头开始评估,导致操作次数等于N的总和(即N +(N-1)+(N-2)+ ... + 1)。对于大的N,这可能会对性能产生很大的影响(更不用说由于递归而生成的堆栈了)。我强烈建议您重新审视这种方法。 - casperOne
嗨@CasperOne。这段代码旨在阐明观点。我并没有写它的目的是为了使其性能更好 - 它只是为了启发Ilya采用其他方法。但再次感谢您指出这一点。 - Aliostad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接