System.Threading.Timer在C#中似乎不工作。 它运行速度非常快,每3秒

我有一个计时器对象。 我希望它每分钟都能运行。 具体来说,它应该运行一个OnCallBack方法,并在运行OnCallBack方法时处于非活动状态。 一旦一个OnCallBack方法完成,它(一个OnCallBack )重新启动一个计时器。

这是我现在所拥有的:

 private static Timer timer; private static void Main() { timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds Console.ReadLine(); } private static void OnCallBack() { timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer Thread.Sleep(3000); //doing some long operation timer.Change(0, 1000 * 10); //restarts the timer } 

但是,这似乎不起作用。 它运行速度非常快,每3秒。 即使如果提高一段时间(1000 * 10)。 它似乎对1000 * 10视而不见

我做错了什么?

这不是System.Threading.Timer的正确用法。 当你实例化定时器时,你应该几乎总是这样做:

 _timer = new Timer( Callback, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite ); 

这将指示计时器在间隔过后只能打勾一次。 然后在您的callback函数中,您可以在工作完成后更改计时器,而不是之前。 例:

 private void Callback( Object state ) { // Long running operation _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite ); } 

因此不需要locking机制,因为没有并发性。 定时器将在下一个时间间隔+长时间运行的时间之后触发下一个callback。

如果您需要在N毫秒的时间内运行计时器,那么我build议您使用秒表来测量长时间运行的时间,然后适当地调用Change方法:

 private void Callback( Object state ) { Stopwatch watch = new Stopwatch(); watch.Start(); // Long running operation _timer.Change( Math.Max( 0, TIME_INTERVAL_IN_MILLISECONDS - watch.ElapsedMilliseconds ), Timeout.Infinite ); } 

强烈鼓励任何人在使用.NET,并且正在使用没有通过C#阅读Jeffrey Richter的书( CLR)的CLR来尽快阅读。 定时器和线程池在那里详细解释。

这是没有必要停止计时器, 从这个post看到很好的解决scheme :

“你可以让定时器继续触发callback方法,但是把你的非重入代码包装在Monitor.TryEnter / Exit中,在这种情况下不需要停止/重启定时器,重叠的调用不会立即获得locking并返回。

 private void CreatorLoop(object state) { if (Monitor.TryEnter(lockObject)) { try { // Work here } finally { Monitor.Exit(lockObject); } } } 

是使用System.Threading.Timer强制?

如果不是,System.Timers.Timer有方便的Start()和Stop()方法(和一个AutoReset属性,你可以设置为false,所以不需要Stop(),你只需在执行后调用Start())。

我只会做:

 private static Timer timer; private static void Main() { timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds Console.ReadLine(); } private static void OnCallBack() { timer.Dispose(); Thread.Sleep(3000); //doing some long operation timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds } 

并且忽略周期参数,因为您正试图自己控制周期。


您的原始代码运行得尽可能快,因为您为dueTime参数指定了0 。 从Timer.Change

如果dueTime为零(0),则立即调用callback方法。

  var span = TimeSpan.FromMinutes(2); var t = Task.Factory.StartNew(async delegate / () => { this.SomeAsync(); await Task.Delay(span, source.Token); }, source.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); source.Cancel(true/or not); // or use ThreadPool(whit defaul options thread) like this Task.Start(()=>{...}), source.Token) 

如果你喜欢使用一些循环线程里面…

 public async void RunForestRun(CancellationToken token) { var t = await Task.Factory.StartNew(async delegate { while (true) { await Task.Delay(TimeSpan.FromSeconds(1), token) .ContinueWith(task => { Console.WriteLine("End delay"); }); this.PrintConsole(1); } }, token) // drop thread options to default values; } // And somewhere there source.Cancel(); //or token.ThrowIfCancellationRequested(); // try/ catch block requred.