使用TPL串行运行几个任务序列

时间:2011-03-18 15:20:13

标签: silverlight asynchronous task-parallel-library

我有一个返回IEnumerable的类。然后我按顺序执行这些任务。假设该类是TaskProvider。

public class TaskProvider {
  public IEnumerable<Task> SomeThingsToDo() { return work; }
}

我正在执行以下操作:

public void ExecuteTasks(IEnumerable<Task> tasks)
{
    var enumerator = tasks.GetEnumerator();
    ExecuteNextTask(enumerator);
}

static void ExecuteNextTask(IEnumerator<Task> enumerator)
{
    bool moveNextSucceeded = enumerator.MoveNext();

    if (!moveNextSucceeded) return;

    enumerator
        .Current
        .ContinueWith(x => ExecuteNextTask(enumerator));
}

现在我的情况是,我可能有多个TaskProvider实例,每个实例都会生成一个任务列表。我希望每个任务列表按顺序执行,这意味着一个提供程序的所有任务在下一个提取程序开始之前完成。

然后,最重要的是,我需要知道所有任务何时完成。

TPL实现这个目标的方式是什么?

(FWIW,我正在使用Silverlight的Async CTP。)

2 个答案:

答案 0 :(得分:1)

这是我采取的方法,到目前为止我所有的测试都已经过去了。

首先,我创建了一个联合各种提供者的所有任务的联合:

var tasks = from provider in providers
            from task in provider.SomeThingsToDo()
            select task;

我认为我原来问题的一部分是我做了一个ToList(或多或少),因此开始过早地执行任务。

接下来,我添加了对ExecuteTasks和ExecuteNextTask的回调。不可否认,并不像我希望的那样干净。以下是修订后的实施:

public void ExecuteTasks(IEnumerable<Task> tasks, Action callback)
{
    var enumerator = tasks.GetEnumerator();
    ExecuteNextTask(enumerator, callback);
}

static void ExecuteNextTask(IEnumerator<Task> enumerator, Action callback)
{
    bool moveNextSucceeded = enumerator.MoveNext();

    if (!moveNextSucceeded)
    {
        if (callback != null) callback();
        return;
    }

    enumerator
        .Current
        .ContinueWith(x => ExecuteNextTask(enumerator, callback));
}

我不需要用于存储任务列表的线程安全结构,因为列表只生成一次。

答案 1 :(得分:0)

在最坏的情况下,你可以拥有一个Ienumerables的静态并发,你可以通过ExecuteNextTask方法来实现它......

类似的东西:

public static class ExecuteController {

    private static ConcurrentQueue<IEnumerable<Task>> TaskLists = new ConcurrentQueue<IEnumerable<Task>>();

    public void ExecuteTaskList(IEnumerable<Task> tasks) {
          TaskLists.Enqueue(tasks);
          TryStartExec();
    }         

    public void TryStartExec() {
         check if there is a new task list and if so exec it with your code. 
         possibly need to lock around the dequeue but i think there is an atomic dequeue method on concurrent queue..
    }

}