Система.Нарезка резьбы.Таймер в C# кажется, не работает. Бегает очень быстро, каждые 3 секунды
у меня есть объект timer. Я хочу его каждую минуту. В частности, он должен запустить OnCallBack
способ и становится неактивным в то время как OnCallBack
метод работает. Раз в OnCallBack
метод заканчивается, это (a 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
что я сделал неправильно?
5 ответов:
Это не правильное использование системы.Нарезка резьбы.Таймер. При создании экземпляра таймера, вы должны почти всегда делать следующее:
_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#, читать как можно скорее. Таймеры и пулы потоков объясняются там очень подробно.
Не нужно останавливать таймер,смотрите хорошее решение из этого поста:
" вы можете позволить таймеру продолжить запуск метода обратного вызова, но обернуть ваш нереентерабельный код в монитор.TryEnter/Выход. В этом случае нет необходимости останавливать/перезапускать таймер; перекрывающиеся вызовы не получат блокировку и не вернутся немедленно."
private void CreatorLoop(object state) { if (Monitor.TryEnter(lockObject)) { try { // Work here } finally { Monitor.Exit(lockObject); } } }
использует систему.Нарезка резьбы.Таймер обязателен ?
Если нет, то система.Таймеры.Таймер имеет удобные методы 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, так как вы пытаетесь контролировать periodicy самостоятельно.
ваш исходный код работает как можно быстрее, так как вы продолжаете указывать
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)
Если вам нравится использовать какую-то петлю внутри ...
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.