Chain ContinueWith任务在运行时

时间:2017-07-21 10:33:07

标签: c# asynchronous task

我试图为我的视图模型创建一个帮助器方法,该方法需要执行一系列操作,并且会阻止同时发生的其他操作集合。

我相信这是使用Task.ContinueWith的主要候选人,而我原来的硬编码功能在使用此方法时没有问题,但是当我尝试在运行时构建操作时,我遇到的问题是任务的运行顺序与我预期的不同。

我的班级看起来像:

internal abstract class ViewModel : IViewModel
{
    private readonly AutoResetEvent autoResetEvent = new AutoResetEvent(true);

    protected Task SynchronousTask(IList<Action> actions)
    {
        var initialTask = new Task(() => this.autoResetEvent.WaitOne());

        for (var i = 0; i < actions.Count; i++)
        {
            var i1 = i;
            initialTask.ContinueWith(task => actions[i1]());
        }

        initialTask.ContinueWith(task => this.autoResetEvent.Set());

        initialTask.Start();
        return initialTask;
    }
}

基本上我想等AutoResetEvent阻止运行任何新任务,直到设置完毕。然后我遍历每个任务,将它们添加为初始任务的延续,最后以延续结束来设置AutoResetEvent

从理论上讲,这看起来应该可行,但是当我运行它时,我最终会以不正确的顺序运行延续。

我知道在不使用ContinueWith的情况下还有其他方法可以做到这一点,但我想知道使用此方法我出错的地点和方式。

2 个答案:

答案 0 :(得分:5)

当你向同一个任务添加多个延续时,就像在你的例子中一样 - 它们按照一定的顺序启动(据我所知,该订单没有记录,你不应该依赖它 - 但似乎它们是按照先出顺序开始的,但是它们不按特定顺序运行。它们启动后 - 它们都并行运行。因此,在您的情况下,所有操作autoResetEvent.Set()几乎会在initialTask完成后同时执行。如果您需要顺序执行 - 只需将所有代码放在一个Task中并运行它,就不需要在这里使用ContinueWith。如果您确实想要使用ContinueWith - 连续延期(对之前ContinueWith的结果调用ContinueWith)。

答案 1 :(得分:2)

您只需要链接到最后一个任务,而不是初始任务。 想象一下,将下一个任务挂钩到上一个任务,而不是将所有任务挂钩到第一个任务。

public static Task SynchronousTask(List<Action> actions)
{
    var initialTask = new Task(() => autoResetEvent.WaitOne());

    Task lastTask = initialTask;
    for (int i = 0; i < actions.Count; i++)
    {
        int i1 = i;
        lastTask = lastTask.ContinueWith(task => actions[i1]()); // here
    }

    lastTask.ContinueWith(task => autoResetEvent.Set());

    initialTask.Start();
    return initialTask;
}