使用秒表创建反击[C#]

时间:2015-02-08 03:37:26

标签: c# timer stopwatch

我想创建counter down,例如每隔10秒,程序将调用一个执行任务的方法。在我使用System.Windows.Forms.Timer和System.Timers.Timer之前,我得到的计数不准确。然后我尝试使用System.Diagnostics.Timer我已经读过这个功能非常准确。 这是我的示例代码

Stopwatch stopWatch = new Stopwatch();
private bool StartTrue = false;
...
private void StartProg_Click(object sender, EventArgs e)
{

StartTrue = true;
StartCounting();
}

private void StartCounting()
{
while(StartTrue)
{
stopWatch.Start();
while(stopWatch.Elapsed.Seconds < 1);
stopWatch.Stop();
stopWatch.Reset();
...
// this part the program for doing task every x second
}
}  

我的程序挂起,cpu使用率很高。先生,我的错误在哪里?或者这样做的更好的方法是什么?

更新: 例如,我想每10秒钟将数据写入串行。当我使用winform计时器或system.timers

10  2/6/2015 6:24:34 PM
9  2/6/2015 6:24:35 PM
8  2/6/2015 6:24:36 PM
7  2/6/2015 6:24:37 PM
6  2/6/2015 6:24:38 PM
5  2/6/2015 6:24:39 PM
4  2/6/2015 6:24:40 PM
3  2/6/2015 6:24:41 PM
2  2/6/2015 6:24:42 PM
1  2/6/2015 6:24:44 PM
10  2/6/2015 6:24:45 PM

计时器滴答是不准确的,在上面,最后一行是当计时器在第80秒触发时。

2 个答案:

答案 0 :(得分:0)

单独使用Stopwatch来衡量时间是低效的,因为您需要在Thread.Sleep上运行busy wait或浪费线程资源。虽然短时间(10毫秒?)间隔可能需要忙碌等待,但您的情况(10秒)似乎并不需要。

计时器的频率远高于执行任务所需的频率,并检查&#34;正确的时间&#34;谈到。即100毫秒的计时器可能足够合理,每隔10秒就能完成一次#34;事件

从理论的角度来看,您需要以这样的方式设置频率,以便在误差范围内至少进行2次检查:即如果您需要10s +/- 0.1s,您的计时器应该至少每0.1s / 2触发一次0.05秒。如果你想进行花哨的采样 - 运行带有可变间隔的计时器 - 9s,0.1s,0.01s关闭你得到所需的时间。您可以从Nyquist–Shannon sampling theorem开始阅读正确的解释。

请注意,Window不是Real-Time-Operating-System,并且不保证任何特定线程有机会在特定时刻执行(即使对于具有更高优先级的线程)。因此,对于大多数与时间相关的操作,您应该预期相对较大的错误(我在相对自由系统上估计30-50ms开始),除非特别注意将其最小化。再过10秒间隔,这可能不是问题。

答案 1 :(得分:0)

谢谢大家。 我在代码中做了一点改动,暂时我会使用这段代码

Timer NewTimer;
int secval;
int tsecs;
...

secVal = int.Parse(BoxSecond.Text);
tsecs = secVal;
NewTimer= new Timer(1000);
NewTimer.Elapsed += NewCounter;

private void TStartStop_Click(object sender, EventArgs e)
{
    ...
    NewTimer.Start();
}

private void NewCounter(Object source, ElapsedEventArgs e)
{
    TimeNow= DateTime.Now;
    if (TimeBefore != null)
    {
        if (TimeNow.Second - TimeBefore.Second == 2)
        {
            tsecs--; 
            ...
            //Invoke for label
        }
        else if (TimeNow.Second - TimeBefore.Second == 0)
        {
            tsecs++;
            ...
            //Invoke for label
        }
    }
    TimeBefore = DateTime.Now;
    ...

    if(tsecs != 0)
    {
        tsecs--;
        //Invoke for label
    }
    else if(tsecs == 0)
    {
        tsecs = secVal;
        tsecs--;
        //Invoke for label
    }
}

比以前更准确