how to execute certain class method no more than once per 100ms?

后端 未结 4 403
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-15 05:51

I\'m writing trading software and need to QoS one method that should not be executed more often than 10 times per second. As I\'m begginer in C# and almost not familar with

相关标签:
4条回答
  • 2021-01-15 06:22

    There is always the System.Timer timer.

    That is probably easier to work with than the Stopwatch (which normally is used to measure how long time things take).

    Code:

        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

    0 讨论(0)
  • 2021-01-15 06:23

    Stopwatches and timers are fairly expensive objects to use. You could simply hold a DateTime object as a variable and perform a comparison.

    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
    }
    
    0 讨论(0)
  • Your technique of using Stopwatch is the best solution to prevent the code from executing more frequently. As others have said, using a Timer is a better solution if you want to make sure that the method is executed on a schedule.

    Any approach based on DateTime is fundamentally broken because it will fail when the date changes. This is especially noticeable during the Daylight Saving Time switches. When we "spring ahead", there's the potential of the update running twice in quick succession because the code thinks that it's been an hour since the previous update. That's not too bad. But when we "fall back", the update will be suspended for a full hour because the last update time is set an hour ahead.

    The same kind of thing can happen, although not as severely, if your computer is set to update its time periodically from an NTP server. If the time is set ahead, then there is the potential for two updates to happen in quick succession. If the time is set back, there's the potential for updates not to happen for the amount of time the clock was set back.

    There are ways around the problem (such as using the absolute value of the number of milliseconds), but then you're just putting a bandage on a broken solution. You shouldn't depend on DateTime for intervals like this because your program isn't in control of the system clock--it can change at any time.

    Stopwatch is the only reasonable solution here because it depends on the CPU's performance counter, which only increases. You don't have the problems of somebody setting the counter back, and you don't have the rollover problems you would encounter with something like Environment.TickCount.

    There's some idea that Stopwatch incurs a performance penalty that DateTime doesn't. My testing shows that to be untrue.

    0 讨论(0)
  • 2021-01-15 06:46

    I would not use a Stopwatch or anything other Timer-like. Instead just store the time of the method call and only execute the subsequent calls if the difference between the current and the stored time is bigger than 100ms.

    You could implement a helper class to do this in a more general way:

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

    Use it like this:

    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");
        }
    }
    
    0 讨论(0)
提交回复
热议问题