【问题标题】:Design for task scheduler in .NET 4 (Task Parallel Library).NET 4(任务并行库)中的任务调度程序设计
【发布时间】:2011-07-20 10:19:21
【问题描述】:

我正在尝试创建一个使用 TPL 以异步(和并行)方式执行计划任务的服务。

基本要求是对于一堆不同的任务,每个任务都有自己的预定速率(一些每秒执行一次,其他 30 秒,其他 5 分钟等)同时执行。而且我不确定解决这个问题的最佳方法,特别是考虑到 ConcurrentBag(我认为它是所有未来任务的持有者)不包含用于选择需要执行的任务集合的方法。

这也意味着我不能使用 WaitAny 或 WaitAll,因为这些短期任务需要独立完成并重新排队。

我应该如何处理这个?

编辑:

好吧,基本上我的设计是这样的:

一个 ScheduledTask,它是具有 Scheduled DateTime 属性的 Task 的包装器。其中一堆存储在 ConcurrentBag 中

一个轮询 ConcurrentBag 的控制器(当前只是一个 while(true) 循环,但可能是一个 Timer 或类似的),删除任何已调度的,并 Start() 的它们。

每个 ScheduledTask 都持有对 ConcurrentBag 的引用,并在完成时将其自身的一个新实例与新的 ScheduledTime 排入队列。

到目前为止,这种设计似乎可行,但是每个 Task 都包含对 ConcurrentBag 的引用,这对我来说并不合适。任何设计 cmets 或建议将不胜感激。

【问题讨论】:

  • 在我看来,您只需使用计时器即可畅通无阻。
  • 什么意思?我将编辑更多信息

标签: .net scheduling task-parallel-library


【解决方案1】:

您是否考虑过使用 RX 的 EventLoopScheduler?

Rx 有很多不同的调度器实现,但 EventLoopScheduler 听起来很适合你。

要使用 RX 创建重复任务,您只需使用 Observable.Interval(timespan, scheduler).Subscribe(action)

【讨论】:

    【解决方案2】:

    您不能使用并发包,因为您需要删除特定项目。

    一种方法是让每个任务看起来像

    MyTask SomeAction() {
        DateTime now = DateTime.Now;
        DoSomeTask();
        return new MyTask { StartTime = now.AddMinutes(1), DoSomething = SomeAction }
    }
    

    调度器看起来像

    List<MyTask> tasklist = new List<MyTask>();
    
    public void Scheduler() {
        for (;;)
            DateTime now = DateTime.Now;
    
            List<MyTask> tasksToRun;
            lock (taskList) 
                taskToRun = taskList.Where(x => x.StartTime <= now)
                                    .ToList();
    
            var tasks = tasksToRun.Select(x => RunTask(x))
                                  .ToArray();
            Thread.Sleep(1000);
        }
    }
    
    private Task<MyTask> RunTask(MyTask myTask) {
        lock (taskList)
            tasklist.Remove(myTask);
    
        return Task<MyTask>.Factory.StartNew(myTask.DoSomething())
                                   .ContinueWith(t => {
                                                          if (t.Result != null)
                                                              lock (taskList)
                                                                  taskList.Add(t.Result);
                                                      });
    }
    

    【讨论】:

    • 这几乎就是我目前所拥有的,尽管我认为我需要将延续从任务内部移动到任务工厂..
    • 我需要在 Where 语句上锁定 taskList 吗?还是就在我添加它的时候?
    • 每次访问都需要锁定列表
    • 我最终修改了我的解决方案,将任务的 Start() 和 ContinueWith() 移到了 TaskController 之外,如上所述。我认为这是一个更优雅的解决方案。塔赫
    【解决方案3】:

    如果您不想自己动手,可以使用http://quartznet.sourceforge.net/

    【讨论】:

    • 从前我也玩得很开心。
    【解决方案4】:

    我使用线程池(虽然不是 TPL)为学校项目编写了一个同步任务调度程序。我从来没有想过让它异步。您可以在单独的后台线程上运行任务并让它执行回调委托。 See here on SourceForge.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多