Разработка планировщика заданий в .NET 4 (Task Parallel Library) - PullRequest
3 голосов
/ 22 марта 2011

Я пытаюсь создать службу, которая выполняет запланированные задачи асинхронным (и параллельным) способом с использованием TPL.

Основным требованием является то, что для множества различных задач, каждая со своими запланированными скоростями(некоторые будут выполняться каждую секунду, другие 30 секунд, другие 5 минут и т. д.), которые будут выполняться одновременно.И я не уверен, что лучше всего это сделать, особенно учитывая, что ConcurrentBag (который я рассматривал как держатель всех будущих задач) не содержит методов, с помощью которых можно выбирать наборы задач, которые необходимо выполнить.

Это также означает, что я не могу использовать WaitAny или WaitAll, так как эти краткосрочные задачи должны завершаться и требовать себя самостоятельно.

Как мне поступить с этим?

Редактировать:

Хорошо, в основном мой дизайн таков:

ScheduledTask, который является оберткой для Task со свойством Scheduled DateTime.Несколько из них хранятся в ConcurrentBag

Контроллере, который опрашивает ConcurrentBag (в настоящее время это просто цикл while (true), но может быть Timer или аналогичным), удаляя все запланированные, и Start ()это их.

Каждый ScheduledTask содержит ссылку на ConcurrentBag и ставит в очередь новый экземпляр самого себя, когда завершается, с новым ScheduledTime.

Этот дизайн, кажется, работает до сих пор, но есть кое-что окаждая задача содержит ссылку на ConcurrentBag, который мне не подходит.Будем благодарны за любые комментарии или предложения по дизайну.

Ответы [ 4 ]

2 голосов
/ 22 марта 2011

Рассматривали ли вы использование EventLoopScheduler из RX?

Rx имеет множество различных реализаций планировщика, но EventLoopScheduler звучит как то, что вам нужно.

Чтобы создать повторяющуюся задачу с RX,вы бы просто использовали Observable.Interval(timespan, scheduler).Subscribe(action).

1 голос
/ 22 марта 2011

Вы можете использовать http://quartznet.sourceforge.net/, если не хотите делать это самостоятельно.

1 голос
/ 22 марта 2011

Вы не можете использовать параллельную сумку, так как вам нужно удалить определенные элементы.

Один из способов сделать это, чтобы каждая задача выглядела как

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);
                                                  });
}
0 голосов
/ 22 марта 2011

Я написал синхронный планировщик задач для школьного проекта с использованием пула потоков (но не TPL). Я никогда не удосужился сделать это асинхронным; Вы можете запускать задачи в отдельном фоновом потоке и заставить его выполнять делегат обратного вызова. Смотрите здесь на SourceForge.

...