2011-04-07 106 views
2

我使用Threading.Timer,如:Threading.Timer麻烦

new System.Threading.Timer(
      new System.Threading.TimerCallback(x=> 
       file.Write(DateTime.Now.ToString()) 
      ), null, 0, 600000); 

而且,例如,它开始于11:00:00,然后我得到的文件:

11:00 :00
11时10分〇〇秒
11时二十零分00秒
...
12点10分〇〇秒
12时19分59秒
12时29分59秒

为什么?从某个时候开始做这样的事情? 我试过其他计时器,如Timers.Timer和winforms Timer,情况也是如此。 令人沮丧。

编辑:解决方案与精确定位器发布在线程中,没有帮助。 怎么样的win32多媒体计时器,它可以帮助吗?

+0

看看这个看看http://stackoverflow.com/questions/897108/how-reliable-are-net-timers和这个http://stackoverflow.com/questions/5015255/reliable-alternative-to-timer- in-net-framework有帮助。 – gideon 2011-04-07 07:33:52

+0

另请参阅:[为什么.NET定时器限制为15毫秒分辨率?](http://stackoverflow.com/questions/3744032/why-are-net-timers-limited-to-15-ms-resolution) – 2011-04-07 08:01:41

回答

3

因为定时器机制并不理想,每次都需要部分时间file.Write(DateTime.Now.ToString()被执行,因此在适当的时候你有一秒的延迟,试着把它留给一个小时,我想你有3个秒钟的延迟即可。

我不知道,每当System.Threading.Timer可以通过跟踪执行时间弥补这一点,ü应该检查选项手动

乘坐看看System.Timers.Timer类也

也试试用这个

class Timer 
{ 
    private Stopwatch sw; 
    private Thread executor; 
    private long interval; 

    public void Start(int intervalInMilliseconds) 
    { 
     interval = intervalInMilliseconds; 
     sw = new Stopwatch(); 
     executor = new Thread(Run); 
     executor.Start(); 
    } 

    public void Run() 
    { 
     while (true) 
     { 
      sw.Start(); 
      Execute(); 
      sw.Stop(); 
      Thread.Sleep((int)(interval - sw.ElapsedMilliseconds)); 
      sw.Reset(); 
     } 
    } 


    public void Execute() 
    { 
     // Do your code here 
    } 

} 
+0

是的。我延迟了15秒,然后我走了一天。我如何使它正常工作?没有人得到这种情况? – 2011-04-07 07:18:35

+0

@Jack:现在工作正常。详情请参阅我的回答。切换到不同的计时器实现(有3个由.NET Framework提供)不会解决这个问题。它在Windows中发生在较低级别。没有人在这里和那里考虑几毫秒的问题。 – 2011-04-07 07:46:15

+0

>虽然(真),但不是最好的解决方案,我认为 – 2011-04-07 07:53:36

0

是的,计时器可能会被其他重要任务所占用。在任何地方都不能保证定时器会按照您设定的时间间隔精确地执行。这只是一个近似的时间间隔,因为Windows是一个多任务操作系统。如果计算机忙于做其他事情,它将无法立即处理您的计时器消息。所以这些消息被放入一个队列中,这可以让它们被推迟,直到它可以这样做。

这就是为什么你应该总是检查一个等于或大于的时间值。它保证减去时间将永不会过去,但不能保证更多时间不会过去。其他的定时器实现没有什么不同。

documentation的用于由Windows API提供的计时器进入更详细地:

一个应用程序使用定时器在规定的时间已经过去之后,以调度的窗口的事件。每当定时器的指定时间间隔(或超时值)过去时,系统都会通知与定时器关联的窗口。由于定时器的精度取决于系统时钟速率以及应用程序从消息队列中检索消息的频率,因此超时值仅为近似值。

Windows根本没有提供这种精确的定时机制。在100个案例中有99个,这根本不相关。对于100分之一的情况,您需要一个实时操作系统。

+0

好的。那么哪里没有图书馆,哪些可以帮助我证明情况?这将为我留下时间& – 2011-04-07 07:48:09

+0

@Jack:你已经在使用可以检查你的时间了。它被称为计时器。问题在于不能保证精确到毫秒。应该预料到一些“漂移”。您显示的数据最多显示*一秒钟的差异。真正的差别可能要小得多,你的代码只是四舍五入到最接近的整数。 – 2011-04-07 07:53:01

+0

对不起。我只是想在适当的时候写入文件。我不能这样做?:( – 2011-04-07 07:55:59

0

这里比较精确的定时器为您提供:

class AccurateTimer 
{ 
    private TimerCallback _Callback; 
    private TimeSpan _Period; 
    private bool _IsWorking = true; 

    public void Stop() 
    { 
     _IsWorking = false; 
    } 

    public AccurateTimer(TimerCallback callback, int period) 
    { 
     _Period = TimeSpan.FromMilliseconds(period); 
     _Callback = callback; 

     new Thread(ThreadMethod).Start(); 
    } 

    private void ThreadMethod() 
    { 
     while (_IsWorking) 
     { 
      var start = DateTime.Now; 
      _Callback.BeginInvoke(null, null, null); 
      Thread.Sleep(_Period - (DateTime.Now - start)); 
     } 
    } 
} 

用法:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var timer = new AccurateTimer(x => Console.WriteLine(DateTime.Now.ToString("h:mm:ss.fff")), 3000); 
     Console.ReadKey(); 
     timer.Stop(); 
    } 
} 

输出:

11:44:46.987 
11:44:49.985 
11:44:52.985 
11:44:55.985 
11:44:58.985 
11:45:01.985 

System.Threading.Timer:

class Program 
{ 
    static void Main(string[] args) 
    { 
     new System.Threading.Timer(x => Console.WriteLine(DateTime.Now.ToString("h:mm:ss.fff")), null, 0, 3000); 
     Console.ReadKey(); 
    } 
} 

输出:

11:50:22.042 
11:50:25.040 
11:50:28.051 
11:50:31.065 
11:50:34.073 
11:50:37.083 
+0

这两个定时器之间的准确度没有任何实际差别 – 2011-04-07 07:59:35

+0

这个例子中的第二个定时器的周期是〜3010ms,而不是3000ms,100次启动后的错误将是1秒 – bniwredyc 2011-04-07 08:08:24

+0

它也会失败。 ..( – 2011-04-08 04:07:47

0

如果你愿意牺牲一些CPU时间,可以使用多媒体计时器(检查this出来,我作为我自己的组件的基础样本C#实现)。

与任何其他.NET定时器或自定义解决方案(通常都必须依赖默认的15.625 ms Windows计时器)不同,它的实际准确度高达1 ms。注意事项:(1)我只能在同一AppDomain中成功创建最多两个此计时器的实例 - 有更多的实例,其中一些实例根本没有引发滴答事件(或稍后)和(2)监视增加的CPU负载,并决定额外的准确性是否值得。