我正在尝试创建一个使用TPL以异步(并行)方式执行计划任务的服务。
基本要求是,对于一系列不同的任务,每个任务都有自己的预定速率(一些要每秒执行一次,另外30秒,其他5分钟等)要同时执行。而且我不确定最好的解决方法,特别是考虑到ConcurrentBag(我考虑将其作为所有未来任务的持有者)不包含用于选择需要执行的任务集合的方法。
这也意味着我不能使用WaitAny或WaitAll,因为这些短期运行的任务需要独立完成并重新排队。
我该如何处理?
编辑:
好的,基本上我的设计是这样的:
ScheduledTask,它是具有Scheduled DateTime属性的Task的包装器。其中一堆存储在ConcurrentBag
中一个控制器,它轮询ConcurrentBag(当前只是一个while(true)循环,但可能是一个Timer或类似的东西),删除任何已调度的,以及Start()的它们。
每个ScheduledTask都包含对ConcurrentBag的引用,并在完成时使用新的ScheduledTime将自身的新实例排入队列。
到目前为止,这个设计似乎有效,但是每个Task都有一些东西,它们对ConcurrentBag的引用并不适合我。任何设计意见或建议将不胜感激。
答案 0 :(得分:2)
您是否考虑过使用RX的EventLoopScheduler?
Rx有许多不同的调度程序实现,但EventLoopScheduler听起来像是适合你的。
要使用RX创建重复任务,您只需使用Observable.Interval(timespan, scheduler).Subscribe(action)
。
答案 1 :(得分:1)
由于您需要删除特定项目,因此无法使用concurrentbag。
一种方法是让每个任务看起来像
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);
});
}
答案 2 :(得分:1)
如果您不想自己动手,可以使用http://quartznet.sourceforge.net/。
答案 3 :(得分:0)
我使用线程池(不是TPL)为学校项目编写了一个同步任务调度程序。我从来没有让它变得异步;您可以在单独的后台线程上运行任务,并让它执行回调委托。 See here on SourceForge.