定时器间隔值较低

本文关键字:定时器 | 更新日期: 2023-09-27 17:49:32

我在c#(WPF)编程。我试着重复调用一个函数。i System.Timers。当我尝试高值的计时器,如1秒= (1000ms),它工作良好,但当我尝试低值它不能工作。

为了显示问题所在,我使用了如下所示的代码:

Timer stopWatchTimer = new Timer();
int timerCounter = 0;
// this method called in button
private void StartStopWatch()
{
    stopWatchTimer.Interval = 1;
    stopWatchTimer.Elapsed += new ElapsedEventHandler(stopWatchTimerElapsed);
    stopWatchTimer.Enabled = true;
}
private void stopWatchTimerElapsed(object sender, ElapsedEventArgs e)
{
    timerCounter++;
    Action a = () =>
    {
        // this is a Label
        lblCounter.Content = timerCounter;
    };
    lblCounter.Dispatcher.Invoke(a);
    if(timerCounter == 200)
    {
        stopWatchTimer.Enabled = false;
    }
}
例如,我使用Label并将间隔设置为200毫秒。所以我的计时器应该停在1秒以内(1/5秒),但它花的时间太长了。问题在哪里?

定时器间隔值较低

定时器的间隔设置为1ms。Windows计时器没有那么高的准确性。在最好的情况下,Windows计时器的精度通常略高于8ms,这意味着你的计时器触发将在+-4 ms或更长时间之间的任何地方关闭。我通常尝试将计时器保持在最大100ms左右,并使用其他更准确的测量失效时间的方法(秒表)来增加计时累加器。

https://msdn.microsoft.com/en-us/library/system.timers.timer.interval%28v=vs.110%29.aspx

您使用Interval属性来确定触发Elapsed事件的频率。因为Timer类依赖于系统时钟,所以它具有与系统时钟相同的分辨率。这意味着,如果interval属性小于系统时钟的分辨率,则Elapsed事件将在由系统时钟分辨率定义的间隔内触发。下面的示例将Interval属性设置为5毫秒。当在系统时钟分辨率大约为15毫秒的Windows 7系统上运行时,该事件大约每15毫秒触发一次,而不是每5毫秒触发一次。

我制作了更精确的计时器,取决于系统滴答计数。

using System;
using System.ComponentModel;
namespace Timers
{
    public class HandmadeTimer
    {
        private int interval = 100;
        private bool enabled = false;
        private BackgroundWorker BGW = new BackgroundWorker();
        public HandmadeTimer(int interval)
        {
            this.interval = interval;
            this.enabled = false;
            this.BGW.WorkerSupportsCancellation = true;
            this.BGW.DoWork += BGW_DoWork;
            this.BGW.WorkerReportsProgress = true;
            this.BGW.ProgressChanged += BGW_ProgressChanged;
        }
        public void Start()
        {
            if (!(enabled))
            {
                enabled = true;
                BGW.RunWorkerAsync();
                StartedEventHandler handler = Started;
                if (!(handler == null))
                    handler();
            }
        }
        public void Stop()
        {
            if (enabled)
            {
                enabled = false;
                BGW.CancelAsync();
                StoppedEventHandler handler = Stopped;
                if (!(handler == null))
                    handler();
            }
        }
        public bool Enabled
        {
            get { return this.enabled; }
            set { if (value)  Start(); else Stop(); }
        }
        public int Interval
        {
            get { return this.interval; }
            set { if (value > 0) this.interval = value; }
        }
        private void BGW_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            long counter = Environment.TickCount + this.interval;
            do
            {
                if (counter <= Environment.TickCount)
                {
                    BGW.ReportProgress(100);
                    counter += this.interval;
                }
            } while (this.enabled);
        }
        private void BGW_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            ElapsedEventHandler handler = Elapsed;
            if (!(handler == null))
                handler();
        }
        public delegate void ElapsedEventHandler();
        public event ElapsedEventHandler Elapsed;
        public delegate void StartedEventHandler();
        public event StartedEventHandler Started;
        public delegate void StoppedEventHandler();
        public event StoppedEventHandler Stopped;
    }
}

更高效,更准确,且免费:p

我希望它有帮助!

DispatcherTimer代替timer

DispatcherTimer myTimer = new DispatcherTimer();
myTimer.Interval = TimeSpan.FromMilliseconds(1);
myTimer.Tick += myTimer_Tick;

所以myTimer_Tick中的每件事都应该每1ms做一次。

  • 请注意,如果您在myTimer_Tick中进行大量计算,则间隔将不准确。
  • 也要注意,如果计算机很忙,它也会产生一些定时器延迟,但你可以玩DispatcherPriority让你的定时器先执行。