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

时间:2012-02-09 18:42:19

标签: 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.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密集。< / p>

任何想法如何以这种方式调用Timer.Stop()/Timer.Start()可能会影响性能(就延迟而言)?

4 个答案:

答案 0 :(得分:5)

使用简单的时间跨度或整数变量作为标志。当计时器滴答时,它会检查一个Stopwatch对象,以查看自该标志最后一次更新以来经过了多长时间。如果它超过你的超时值,你就会触发看门狗代码。

现在,当新数据包进入时,其他代码可以使用秒表更新您的时间跨度标志值,而不是重置您的计时器。

您还应该将计时器的滴答间隔设置为您希望实际超时持续时间的1/2,或者在事件中设置代码来设置您的间隔,以便您的下一个滴答事件仅在您之后的几毫秒如果连接现在被切断,将会超时。否则,在最后一个数据包在嘀嗒事件发生后很快到达的情况下,你最终可能会等待超过两倍的时间。

答案 1 :(得分:2)

顺便说一下,另一个选项就是只要有一个Boolean标志,只要有消息进入就会设置该标志。定时器事件处理程序会检查该标志并在没有设置时发出警告。所以你有:

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

答案 2 :(得分:1)

更简单的选项是调用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;
        }
    }
}

答案 3 :(得分:0)

  

任何想法如何调用Timer.Stop() / Timer.Start()

     

这种方式可能会影响性能(就延迟而言)?

<强>无

不太可能测量执行此操作所需的资源量。除非遇到性能问题,否则不要尝试解决性能问题,至少要使用软件来分析软件,看看它是否存在实际问题。