C#计时器的密集停止/启动

C#计时器的密集停止/启动,c#,performance,timer,C#,Performance,Timer,我创建了一个看门狗计时器(使用System.Windows.Forms.timer),如果长时间过期而没有接收到一小包数据,它就会触发: using System.Windows.Forms; public class Watchdog { private Timer Timer; public void Go() { Timer.Start(); } public void Reset() { Timer.St

我创建了一个看门狗计时器(使用System.Windows.Forms.timer),如果长时间过期而没有接收到一小包数据,它就会触发:

using System.Windows.Forms;
public class Watchdog
{
    private Timer Timer;

    public void Go()
    {
        Timer.Start();
    }

    public void Reset()
    {
        Timer.Stop();
        Timer.Start();
    }

    private void OnTimerExpired(object State)
    {
        Timer.Stop();
        DoSomething();
    }

    public Watchdog()
    {
        Timer = new Timer();
        Timer.Tick += new EventHandler(OnTimerExpired);
        Timer.Interval = (1000 * Timeout);            
    }
}
主代码调用
Go()
,然后在每次收到数据包时调用
Reset()
。如果计时器过期,则调用
OnTimerExpired()

由于每秒可能有数百个数据包接收,并且应用程序的主要任务是响应这些数据包,因此我开始怀疑重置计时器是否不是CPU/OS密集型的


知道用这种方式调用
Timer.Stop()/Timer.Start()
会如何影响性能(在延迟方面)吗?

使用一个简单的timespan或整数变量作为标志。当计时器滴答作响时,它会检查秒表对象,以查看自上次使用该标志以来经过了多少时间。如果超过超时值,则触发看门狗代码

现在,当一个新数据包进来时,其他代码可以使用秒表来更新timespan标志值,而不是重置计时器

您还应该将计时器的滴答声间隔设置为实际超时持续时间的1/2左右,或者在事件中设置代码来设置间隔,以便在连接现在断开时,下一个滴答声事件仅在超时几毫秒后发生。否则,在最后一个数据包在滴答声事件后很快到达的情况下,您可能最终等待的时间几乎是超时时间的两倍

知道如何调用
Timer.Stop()
/
Timer.Start()

这种方式可能会影响性能(在延迟方面)


完成这项工作所需的资源量不太可能衡量。除非您有性能问题,否则不要试图解决性能问题,至少要使用软件来分析软件是否存在实际问题。

另一种选择是,只要在收到消息时设置一个
布尔
标志。计时器事件处理程序检查该标志,如果未设置,则发出警报。所以你有:

private bool GotAMessage = false;

void MessageReceived()
{
    // happens whenever a message is received
    GotAMessage = true;
}

void OnTimerExpired(object state)
{
    if (!GotAMessage)
    {
        // didn't receive a message in time.
    }
    GotAMessage = false;
}

一个更简单的选项是调用WatchDog类上的方法,该方法在收到数据包时更新公共lastPacketReceived值。然后,您只需要在WatchDog类中启动一个计时器,该计时器在每个超时间隔内滴答一次,并将当前时间与lastPacketReceived值进行比较:

public static class WatchDog
{
    static object locker = new object();
    static long lastPacketReceived;
    static Stopwatch stopWatch = new Stopwatch();
    static long threshold = 5000;
    static WatchDog()
    {
        Timer watchDogTimer = new Timer(1000);
        watchDogTimer.Elapsed += new ElapsedEventHandler(watchDogTimer_Elapsed);
        watchDogTimer.Start();
        stopWatch.Start();
    }

    static void watchDogTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        lock (locker)
        {
            if ((stopWatch.ElapsedMilliseconds - lastPacketReceived) > threshold)
            {
                // threshold exceeded
            }
        }
    }

    public static void PacketReceived()
    {
        lock (locker)
        {
            lastPacketReceived = stopWatch.ElapsedMilliseconds;
        }
    }
}

不要为此使用
DateTime
!在夏令时转换期间,以及如果用户更改时钟,您将遇到问题。您最好在程序启动时启动秒表,并在每次收到消息时保存其已用时间值。然后,计时器滴答声可以将当前的
已用时间
值与上次收到的消息值进行比较。您是否最好使用
System.Debug.Stopwatch
类?