【问题标题】:Running several sequences of Tasks serially using TPL使用 TPL 串行运行多个任务序列
【发布时间】:2011-03-19 02:52:29
【问题描述】:

我有一个返回 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 使用异步 CTP。)

【问题讨论】:

  • 我也想知道我是否正在用我的 ExecuteTask 逻辑重新发明轮子。

标签: silverlight asynchronous task-parallel-library


【解决方案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));
}

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

【讨论】:

    【解决方案2】:

    在最坏的情况下,您可能有一个静态的 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..
        }
    
    }
    

    【讨论】:

    • ConcurrentQueue 在 Silverlight(或新的异步 ctp 库中)中不存在。虽然我现在正在根据您的回答尝试类似的方法。
    猜你喜欢
    • 2012-11-02
    • 2014-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多