Threading.Timer麻烦

时间:2011-04-07 07:11:35

标签: .net windows 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时十分00秒
11时20分○○秒
...
12时10分00秒
12点十九分59秒
12时29分59秒

为什么呢?从一段时间开始做这样的事情? 我尝试过其他计时器,比如Timers.Timer,以及winforms,同样的情况。 这令我很郁闷。

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

4 个答案:

答案 0 :(得分:3)

因为定时器机制不理想,每次执行文件时都需要一部分时间.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
    }

}

答案 1 :(得分:0)

是的,计时器可能会受到其他重要任务的抢占。无处可以保证计时器将在您设置的时间间隔内精确地执行 。它只是一个近似的间隔,因为Windows是一个多任务操作系统。如果计算机正在忙于执行其他操作,则无法立即为您的计时器消息提供服务。因此消息被放入队列,这允许它们被推迟,直到它可以这样做。

这就是为什么你应该总是检查一个等于或大于你想要的时间的时间值。保证 less 时间永远不会过去,但不能保证更多时间不会过去。其他计时器实现也不例外。

Windows API提供的计时器的documentation更详细:

  

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

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

答案 2 :(得分: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

答案 3 :(得分:0)

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

您会发现它的实际精度最高可达1毫秒,这与其他任何.NET计时器或自定义解决方案不同,后者始终必须依赖于默认的15.625毫秒Windows计时器。

注意事项:(1)我只能在同一个AppDomain中成功创建多达2个此计时器实例 - 有更多实例,其中一些实际上根本没有提高刻度事件(或者很短的时间) ,(2)监控增加的CPU负载并确定额外的准确性是否值得。