如果计时器运行时间超过计时器间隔,计时器将终止任务/作业
Posted
技术标签:
【中文标题】如果计时器运行时间超过计时器间隔,计时器将终止任务/作业【英文标题】:Timer kills task/job if it runs longer than timer interval 【发布时间】:2013-08-03 09:56:17 【问题描述】:我想做一个行为如下的计时器:
如果任务/作业的处理时间小于计时器间隔,则在(timer.interval - 处理时间作业/作业)中启动计时器
如果作业/任务的处理时间超过定时器间隔,立即启动下一个作业/任务
下面的代码有效,但我想知道为什么在 ElapsedEventHandler 方法中作业/任务必须首先完成,然后我们可以设置新的计时器间隔。 System.Timers.Timer 的 Elapsed 事件在间隔已过时引发。使用 AutoReset = false 选项,我们设置 Timer 仅在第一个 Interval 过去后引发 Elapsed 事件一次。然后我们必须手动调用 Timer.Start() 来重新启动它。
using System;
using System.Timers;
namespace TestTimer
class Program
private static Timer t;
private static double intervalMiliseconds;
static void Main(string[] args)
intervalMiliseconds = 5000; // 5 seconds
t = new Timer();
t.Interval = intervalMiliseconds;
t.AutoReset = false;
t.Elapsed += new ElapsedEventHandler(OnTimedEvent);
t.Start();
log("Timer started at " + DateTime.Now.ToString());
log("Interval is: " + defaultIntervalMiliseconds);
Console.ReadKey();
private static void log(string text)
Console.WriteLine(text + "\n");
private static void OnTimedEvent(object source, ElapsedEventArgs e)
// if t.Interval is set here thread just kills the job if it
// runs longer than interval
t.Interval = intervalMiliseconds;
log("ElapsedEvent triggered at " + DateTime.Now.ToString());
// job
DateTime startTime = DateTime.Now;
log("job started" );
System.Threading.Thread.Sleep(8000); // 8 sec
log("job ended" );
TimeSpan jobTime = DateTime.Now.Subtract(startTime);
log("job took " + jobTime.TotalSeconds + " seconds");
// if we set t.Interval here it works so first the job
// must be done and than we can set timer interval ? why ?
//t.Interval = intervalMiliseconds;
if (jobTime.TotalMilliseconds < t.Interval)
t.Interval = t.Interval - jobTime.TotalMilliseconds;
log("Job ended Earlier starting Event in: " + t.Interval);
else
t.Interval = 100;
log("Job overpass interval. Current time: " +
DateTime.Now.ToString());
t.AutoReset = false;
t.Start();
结果:
如果我们在方法 OnTimedEvent 的开头注释 t.Interval 并在工作完成后取消注释 t.Interval 一切正常。结果:
为什么我们不能在方法 OnTimedEvent 的开始设置定时器间隔。如果我们在任务/作业运行时间超过计时器间隔的情况下这样做,线程只会终止该作业。如果有人有一些想法,我将不胜感激?这是否与线程与主线程(哪个计时器运行)的同步有关?当我们调用方法 OnTimedEvent 时,定时器不会再次调用该方法,因为它具有 AutoReset = false,那么设置定时器属性有什么区别?
【问题讨论】:
我还没有读完你的整个问题,但为什么不在工作的 start 处启动计时器。当作业完成时,如果计时器已过,则启动另一个作业,否则等待计时器到时。 【参考方案1】: t.Interval = intervalMiliseconds;
这确实是麻烦制造者。这是非常不直观的行为,Timer.Interval 的MSDN article 在注释中特别警告:
如果 Enabled 和 AutoReset 都设置为 false,并且之前已启用计时器,则设置 Interval 属性会导致 Elapsed 事件引发一次,就像 Enabled 属性已设置为 true 一样。要设置间隔而不引发事件,您可以将 AutoReset 属性临时设置为 true。
这是一个相当愚蠢的 hack,但确实有效。只是延迟分配值肯定是更好的方法。早点做不会给你带来任何好处,除了麻烦之外,由于你设置了 AutoReset = false,因此计时器无论如何都不会滴答作响。
System.Threading.Timer 是更好的计时器类,具有更少的怪癖。它不会在回调方法中没有任何诊断的情况下吞下异常。您的代码对哪个非常敏感,计时器将停止计时,因为异常绕过了 t.Start() 调用,您不知道为什么。强烈推荐。
【讨论】:
【参考方案2】:!!如果运行时间超过计时器间隔,则不会,也永远不会计时器终止任务/作业!
如果任务/作业的处理时间小于计时器间隔, 在计时器间隔/跨度之后。 如果作业/任务的处理时间超过计时器间隔, 在计时器间隔/跨度后启动下一个作业/任务进入新线程。
因此,为了尽量减少空闲时间,您应该保持较小的计时器间隔。 在 System.Timers.Timer 类内部已经实现了 Threading。所以不需要实现线程。
【讨论】:
您好,欢迎来到 Stack Overflow,首先感谢您花时间回答。请花点时间通过welcome tour 了解您的方法,阅读How to Answer 以创建有用的答案并添加到社区中。以上是关于如果计时器运行时间超过计时器间隔,计时器将终止任务/作业的主要内容,如果未能解决你的问题,请参考以下文章
C# - 在需要时从多个运行的计时器中处理一个特定的计时器[关闭]