如何每100ms执行一次类方法不超过一次?

时间:2011-04-15 14:32:23

标签: c#

我正在编写交易软件,并且需要QoS一种不应该每秒执行10次以上的方法。由于我是C#的初学者并且几乎不熟悉库,我想仔细检查我的代码是否“最佳”。我正在使用Stopwatch,因为我不知道C#中的任何其他计时器。

    Stopwatch updateStopwatch = Stopwatch.StartNew();

    private void update()
    {
        if (updateStopwatch.ElapsedMilliseconds < 100)
        {
            Console.WriteLine("!skip update " + updateStopwatch.ElapsedMilliseconds);
            return;
        } else
        {
            Console.WriteLine("!update");
            updateStopwatch.Restart();;
        }
        // do work here
    }

upd 现在看来,秒表非常适合这项任务。然而,可能它会太慢,如果可能的话,DateTime会更好。也卖Stopwatch vs. using System.DateTime.Now for timing events

4 个答案:

答案 0 :(得分:2)

使用Stopwatch的技巧是防止代码更频繁执行的最佳解决方案。正如其他人所说,如果你想确保按计划执行方法,使用Timer是一个更好的解决方案。

任何基于DateTime的方法都会从根本上被打破,因为它会在日期更改时失败。这在夏令时开关期间尤其明显。当我们“向前迈进”时,更新可能会快速连续运行两次,因为代码认为自上次更新以来已经过了一个小时。那不算太糟糕。但是当我们“退回”时,更新将暂停一整小时,因为上次更新时间是提前一小时设置的。

如果您的计算机设置为定期从NTP服务器更新其时间,则可能会发生同样的情况,尽管不是那么严重。如果时间提前,则可能会快速连续发生两次更新。如果时间被设置回来,则可能会在时钟被设置的时间内发生更新。

有很多方法可以解决这个问题(例如使用毫秒数的绝对值),但是你只是在一个破碎的解决方案上加上绷带。您不应该依赖DateTime这样的间隔,因为您的程序无法控制系统时钟 - 它可以随时更改。

Stopwatch是唯一合理的解决方案,因为它取决于CPU的性能计数器,它只会增加。您没有让某人设置计数器的问题,并且您没有遇到类似Environment.TickCount之类的翻转问题。

有些人认为Stopwatch会导致DateTime没有的性能损失。我的测试表明这是不真实的。

答案 1 :(得分:1)

秒表和计时器是相当昂贵的对象。您可以简单地将DateTime对象作为变量并执行比较。

DateTime lastCheck = DateTime.Now;

private void update()
{
    // DateTime.Subtract returns a TimeSpan
    int elapsed = DateTime.Now.Subtract(lastCheck).Milliseconds;
    if (elapsed < 100)
    {
        Console.WriteLine("!skip update " + elapsed.ToString());
        return;
    } else
    {
        Console.WriteLine("!update");
        lastCheck = DateTime.Now;
    }
    // do work here
}

答案 2 :(得分:1)

我不会使用Stopwatch或其他任何Timer - 就像。而只是存储方法调用的时间,并且只有当前和存储时间之间的差异大于100ms时才执行后续调用。

您可以实现一个帮助程序类,以更一般的方式执行此操作:

public class TimedGate
{
     private DateTime m_Last;
     private TimeSpan m_Gap;

     public TimedGate(TimeSpan gap)
     {
         m_Gap = gap;
     }

     public bool TryEnter()
     {            
         DateTime now = DateTime.UtcNow;
         if (now.Subtract(m_Last) > m_Gap)
         {
              m_LastEntered = now;   
              return true;                 
         }
         return false;  
     }
}

像这样使用:

TimedGate m_UpdateGate = new TimedGate(TimeSpan.FromMilliseconds(100));

private void Update()
{
    if (m_UpdateGate.TryEnter())
    {
        Console.WriteLine("!update");

        // do work here
    }
    else
    {
        Console.WriteLine("!skip update");
    }
}

答案 3 :(得分:0)

始终有System.Timer计时器。

这可能比秒表更容易使用(通常用于衡量事情需要多长时间)。

代码:

    var timer = new System.Timers.Timer();

    // Hook up the Elapsed event for the timer using a lambda
    timer.Elapsed += (o, e) => Console.WriteLine("Timer elapsed");

    // Set the Interval to 100 ms
    timer.Interval = 100;

    // Start the timer.
    timer.Enabled = true;

MSDN文档:http://msdn.microsoft.com/en-us/library/system.timers.timer(v=VS.100).aspx