简体   繁体   中英

Design for task scheduler in .NET 4 (Task Parallel Library)

I'm trying to create a service that executes scheduled Tasks in an asynchronous (and parallel) way using TPL.

The basic requirement is that for a bunch of different tasks, each with their own scheduled rates (some to be executed every second, others 30 seconds, other 5 mins etc) to be executed concurrently. And I'm not sure of the best way to go about this, especially considering the ConcurrentBag (which I was considering as a holder of all future tasks) contains no methods with which to select collections of tasks that need to be executed.

It also means that I can't use WaitAny or WaitAll, as these short-running tasks need to finish and requeue themselves independently.

How should I proceed with this?

Edit:

Ok basically my design is thus:

A ScheduledTask, which is a wrapper for Task with a Scheduled DateTime property. A bunch of these are stored in a ConcurrentBag

A Controller that polls the ConcurrentBag (currently just a while(true) loop, but could be a Timer or similar), removing any that are scheduled, and Start()'s them.

Each ScheduledTask holds a reference to the ConcurrentBag, and enqueues a new instance of itself when it completes, with a new ScheduledTime.

This design seems to work so far, but there is something about each Task holding a reference to the ConcurrentBag that doesn't sit well with me. Any design comments or suggestions would be appreciated.

Have you considered using the EventLoopScheduler from RX?

Rx has lots of different scheduler implementations, but EventLoopScheduler sounds like the right one for you.

To create a repeating task with RX, you'd just use Observable.Interval(timespan, scheduler).Subscribe(action) .

You can't use a concurrentbag since you need to remove specific items.

One way to do it is to let each task look like

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

the scheduler will look something like

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);
                                                  });
}

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

I wrote a synchronous task scheduler for a school project using the thread pool (not TPL though). I never got around to making it async; you could run the tasks on a separate background thread and have it execute a callback delegate. See here on SourceForge.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM