线程。定时器麻烦

我正在使用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时十分00秒
11时20分○○秒

12时10分00秒
12点十九分59秒
12时29分59秒

为什么? 从某个时候开始做这样的事情? 我试过其他的定时器,比如Timers.Timer和winforms Timer,情况也是一样的。 这令我郁闷。

编辑:解决scheme与精确的时间线张贴,没有帮助。 怎么样的win32多媒体计时器,它可以帮助吗?

因为定时器机制并不理想,所以每次都需要部分时间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 } } 

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

这就是为什么你应该总是检查一个等于或大于你期望的时间值。 保证更少的时间永远不会流逝,但不能保证更多的时间不会流逝。 其他的定时器实现没有什么不同。

由Windows API提供的定时器的文档更详细:

应用程序使用计时器在指定时间过后安排窗口的事件。 每当定时器的指定时间间隔(或超时值)超时,系统都会通知与定时器相关的窗口。 由于定时器的精度取决于系统时钟速率以及应用程序从消息队列中检索消息的频率,所以超时值仅为近似值。

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

如果你愿意牺牲一些CPU时间,你可以使用多媒体计时器(查看一下我用作自己组件基础的C#实现实例)。

你会发现它的实际精度高达1毫秒,不像任何其他的.NET定时器或自定义的解决方案,总是必须依靠默认的Windows 15.625毫秒计时器。

注意事项:(1)我只能在同一个AppDomain中最多创建2个这个定时器的实例 – 有更多的实例,其中一些实际上并没有引发滴答事件(或稍后), 2)监视增加的CPU负载,并决定是否额外的准确性是值得的。

这里有更准确的计时器给你:

 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