如何每100毫秒执行一个类方法不超过一次

本文关键字:类方法 不超过 一次 一个 何每 执行 100毫 | 更新日期: 2023-09-27 17:50:13

我正在编写交易软件,需要为一种每秒执行次数不应超过10次的方法提供QoS。由于我是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现在看来Stopwatch非常适合这个任务。然而,它可能太慢了,如果是这样的话,DateTime可能会更好。也出售Stopwatch与使用System.DateTime.Now计时事件

如何每100毫秒执行一个类方法不超过一次

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

任何基于DateTime的方法都是从根本上被破坏的,因为当日期改变时它将失败。这在夏令时切换时尤其明显。当我们"提前"时,更新可能会连续运行两次,因为代码认为距离上一次更新已经过去了一个小时。还不错。但是当我们"后退"时,更新将被暂停整整一个小时,因为最后一次更新时间被设置为提前一个小时。

如果您的计算机设置为定期从NTP服务器更新其时间,那么同样的事情也会发生,尽管没有那么严重。如果提前设定了时间,那么就有可能在短时间内连续进行两次更新。如果将时间设置回调,则有可能在时钟设置回调的时间内不会发生更新。

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

Stopwatch是这里唯一合理的解决方案,因为它取决于CPU的性能计数器,它只会增加。你不会遇到有人设置计数器的问题,也不会遇到Environment.TickCount之类的东西会遇到的翻转问题。

有人认为Stopwatch会导致DateTime不会带来的性能损失。我的测试表明这是不正确的。

秒表和计时器是使用起来相当昂贵的对象。您可以简单地将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
}

我不会使用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");
    }
}

总是有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 docs: http://msdn.microsoft.com/en-us/library/system.timers.timer(v=VS.100).aspx