我正在.NET中开发一个Windows服务应用程序,它执行许多功能(它是一个WCF服务主机),其中一个目标是运行计划任务。
我选择为每个操作创建一个System.Threading.Timer,将dueTime设置为下一次执行,没有时间段以避免重入。
每次操作结束时,它都会更改dueTime以匹配下一个计划执行。
大多数操作计划每分钟运行一次,而不是所有操作都会相继延迟几秒钟。
现在,在添加了大约30个操作之后,似乎定时器开始变得不准确,开始操作很晚几秒,甚至几分钟。
我正在计时器的回调方法中直接运行操作逻辑,因此正在运行的线程应与计时器相同。
我应该创建一个任务来运行操作而不是在回调方法中运行它来提高准确性吗?
或者我应该使用具有固定(1秒)dueTime的单个计时器来检查需要启动哪些操作? 我不喜欢这最后一个选项,因为处理重入会更加困难。
答案 0 :(得分:1)
Timers触发一个线程池线程,所以你可能会发现,当你添加大量的定时器时,你正在耗尽线程池。
您可以increase线程池的大小,或者确保您的计时器少于线程池大小。
从回调中解雇任务可能无济于事 - 因为你将要争取来自同一线程池的线程。除非您使用long-running tasks。
答案 1 :(得分:1)
我们通常会设置多个计时器来处理单个服务中的不同操作。我们设置间隔并启动,停止服务启动/停止/关闭事件的计时器(并有一个变量指示每个事件的状态,即bool Stopped) 当计时器结束时,我们停止计时器,运行处理(这可能需要一段时间,具体取决于过程,即如果它的短路可能需要比间隔更长的时间..(此代码需要尝试 - 捕获所以它一直在发生错误) 代码处理完毕后,我们检查Stopped变量,如果它没有停止,我们再次启动计时器(这会处理你提到的重入,并允许代码尽可能地保持间隔) 据我所知,定时器在大约100ms后通常更准确,但应该足够接近你想做的事情。
我们已经运用了这个概念多年,它并没有让我们失望。
如果您将这些任务作为ASP.NET应用程序的子系统运行,您还应该查看HangFire,它可以处理后台处理,无需使用Windows服务。
计时器需要多准确?你总是可以使用单个计时器并同时运行多个处理线程?如果不那么重要,可以将调用排入某些操作。
答案 2 :(得分:0)
好的,我做出了一个决定:由于我无法轻易重现这种行为,我选择解决根问题并仅使用服务流程:
每个可以吃CPU的操作都由另一个进程执行,该进程由主进程(使用System.Diagnostics.Process及其事件)直接控制,并通过WCF与之通信。
当我启动辅助进程时,我通过命令行传递主进程的PID。如果后者被杀死,则会触发Process.Exited事件,我也可以关闭子进程。
这样主要的服务通常不会占用大量的CPU时间,而且可以随意安排,而且没有延迟。
感谢所有给我一些建议的人!