System.Threading.Timer в C #, похоже, не работает. Он работает очень быстро каждые 3 секунды

У меня есть объект таймера. Я хочу, чтобы он запускался каждую минуту. В частности, он должен запускать метод OnCallBack и становится неактивным при 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 ); 

Это даст указание таймеру указывать только один раз, когда интервал истек. Затем в вашей функции обратного вызова вы меняете таймер после завершения работы, а не раньше. Пример:

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

Таким образом, нет необходимости в механизмах блокировки, поскольку параллелизм отсутствует. Таймер активирует следующий обратный вызов после истечения следующего интервала + время продолжительной операции.

Если вам нужно запустить свой таймер ровно в N миллисекундах, то я предлагаю вам измерить время длительной работы с помощью секундомера, а затем вызвать метод изменения соответствующим образом:

 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, и использует CLR, который не читал книгу Джеффри Рихтера – CLR через C # , чтобы прочитать это как можно скорее. Здесь подробно описаны таймеры и пулы streamов.

Нет необходимости останавливать таймер, см. Хорошее решение из этого сообщения :

«Вы можете позволить таймеру продолжать активировать метод обратного вызова, но оберните свой невозвратный код в Monitor.TryEnter / Exit. Нет необходимости останавливать / перезапускать таймер в этом случае, перекрывающиеся вызовы не будут получать блокировку и немедленно возвращаться».

 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 } 

И игнорируйте параметр period, так как вы пытаетесь самостоятельно управлять периодикой.


Ваш исходный код работает как можно быстрее, так как вы продолжаете указывать 0 для параметра dueTime . Из Timer.Change :

Если dueTime равно нулю (0), метод обратного вызова вызывается немедленно.

  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) 

если вы любите использовать какой-то stream цикла внутри …

 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. 
  • java.util.Timer: устарел ли он?
  • Как отключить stream
  • Выполняется ли в System.Windows.Forms.Timer другой stream, чем пользовательский интерфейс?
  • Как вызвать метод пользовательского интерфейса из другого streamа
  • Java Animate JLabel
  • Остановить секундомер
  • Как установить таймер в Java?
  • Являются ли таймеры и петли в .Net точными?
  • Функция таймера для обеспечения времени в наносекундах с использованием C ++
  • Android: доступ к элементу пользовательского интерфейса из streamа таймера
  • Java Timer vs ExecutorService?
  • Давайте будем гением компьютера.