Внимание: ответы здесь содержат ошибку, объект Timer будет собирать мусор. Ссылка на таймер должна храниться в статической переменной, чтобы гарантировать, что он продолжает работать.
Ханс Пассан
@HansPassant Похоже, вы пропустили четкое заявление в моем ответе: «Также рекомендуется всегда использовать статический (общий в VB.NET) System.Threading.Timer, если вы разрабатываете службу Windows и вам требуется, чтобы таймер периодически запускался. . Это позволит избежать, возможно, преждевременной сборки мусора вашего объекта таймера. " Если люди хотят скопировать случайный пример и использовать его вслепую, это их проблема.
Эш
Ответы:
120
Это очень хорошо, однако для имитации прохождения некоторого времени нам нужно запустить команду, которая требует времени, и это очень ясно во втором примере.
Однако стиль использования цикла for для выполнения некоторых функций навсегда требует много ресурсов устройства, и вместо этого мы можем использовать сборщик мусора, чтобы делать что-то подобное.
Мы можем видеть эту модификацию в коде из той же книги CLR Via C # Third Ed.
using System;
using System.Threading;publicstaticclassProgram{publicstaticvoidMain(){// Create a Timer object that knows to call our TimerCallback// method once every 2000 milliseconds.Timer t =newTimer(TimerCallback,null,0,2000);// Wait for the user to hit <Enter>Console.ReadLine();}privatestaticvoidTimerCallback(Object o){// Display the date/time when this method got called.Console.WriteLine("In TimerCallback: "+DateTime.Now);// Force a garbage collection to occur for this demo.
GC.Collect();}}
Халид, это было чрезвычайно полезно. Спасибо. Console.readline () и GC.Collect были именно тем, что мне было нужно.
Сет Спирмен
9
@ Ральф Уиллгосс, Почему GC.Collect (); необходимо?
Puchacz
2
@Puchacz Я не вижу смысла звонить GC.Collect(). Собирать нечего. Это имело бы смысл, если бы GC.KeepAlive(t)назвали послеConsole.ReadLine();
газета
1
Он
прервался
1
@Khalid Al Hajami «Однако стиль использования цикла for для выполнения некоторых функций навсегда требует много ресурсов устройства, и вместо этого мы можем использовать сборщик мусора, чтобы делать что-то подобное». Это полная чушь. Сборщик мусора совершенно не важен. Вы скопировали это из книги и не понимаете, что копируете?
Эш
66
Используйте класс System.Threading.Timer.
System.Windows.Forms.Timer предназначен в первую очередь для использования в одном потоке, обычно это поток пользовательского интерфейса Windows Forms.
Существует также класс System.Timers, добавленный на ранних этапах разработки платформы .NET. Однако обычно рекомендуется использовать вместо него класс System.Threading.Timer, так как в любом случае это просто оболочка для System.Threading.Timer.
Также рекомендуется всегда использовать статический (общий в VB.NET) System.Threading.Timer, если вы разрабатываете службу Windows и вам требуется периодический запуск таймера. Это позволит избежать возможной преждевременной сборки мусора вашего объекта таймера.
Вот пример таймера в консольном приложении:
using System;
using System.Threading;publicstaticclassProgram{publicstaticvoidMain(){Console.WriteLine("Main thread: starting a timer");Timer t =newTimer(ComputeBoundOp,5,0,2000);Console.WriteLine("Main thread: Doing other work here...");Thread.Sleep(10000);// Simulating other work (10 seconds)
t.Dispose();// Cancel the timer now}// This method's signature must match the TimerCallback delegateprivatestaticvoidComputeBoundOp(Object state){// This method is executed by a thread pool thread Console.WriteLine("In ComputeBoundOp: state={0}", state);Thread.Sleep(1000);// Simulates other work (1 second)// When this method returns, the thread goes back // to the pool and waits for another task }}
Из книги Джеффа Рихтера CLR Via C # . Между прочим, эта книга описывает обоснование трех типов таймеров в главе 23, настоятельно рекомендуется.
Эрик, я не пробовал, но не было бы ничего необычного, если бы с этим возникла проблема. Я заметил, что он также пытается выполнить какую-то межпотоковую синхронизацию, это всегда область, в которой может быть сложно разобраться. Если вы можете избежать этого в своем дизайне, это всегда будет разумно.
Эш,
1
Эш - Я определенно согласен с примерами msdn. Я бы не стал сразу сбрасывать со счетов код синхронизации, если таймер работает в собственном потоке, значит, вы пишете многопоточное приложение и вам нужно знать о проблемах, связанных с синхронизацией.
Эрик Таттлман,
1
Что произойдет, если существует несколько методов, соответствующих сигнатуре делегата TimerCallback?
Ozkan
22
Вот код для создания простого таймера на одну секунду:
using System;
using System.Threading;classTimerExample{staticpublicvoidTick(Object stateInfo){Console.WriteLine("Tick: {0}",DateTime.Now.ToString("h:mm:ss"));}staticvoidMain(){TimerCallback callback =newTimerCallback(Tick);Console.WriteLine("Creating timer: {0}\n",DateTime.Now.ToString("h:mm:ss"));// create a one second timer tickTimer stateTimer =newTimer(callback,null,0,1000);// loop here foreverfor(;;){// add a sleep for 100 mSec to reduce CPU usageThread.Sleep(100);}}}
РЕДАКТИРОВАТЬ: никогда не рекомендуется добавлять жесткие циклы вращения в код, поскольку они потребляют циклы процессора без какой-либо выгоды. В этом случае этот цикл был добавлен только для того, чтобы остановить закрытие приложения, чтобы можно было наблюдать за действиями потока. Но для правильности и уменьшения загрузки ЦП в этот цикл был добавлен простой вызов режима сна.
For (;;) {} вызывает 100% использование процессора.
Сет Спирмен
1
Разве это не очевидно, если у вас есть бесконечный цикл for, тогда это приведет к 100% загрузке ЦП. Чтобы исправить это, все, что вам нужно сделать, это добавить в цикл вызов сна.
2013,
3
Удивительно, сколько людей зацикливаются на том, должен ли цикл for быть циклом while и почему ЦП переходит на 100%. Поговорим о том, чтобы пропустить лес за деревьями! Азимут, я лично хотел бы знать, чем время (1) будет отличаться от бесконечного цикла for? Конечно, люди, которые пишут оптимизатор компилятора CLR, будут уверены, что эти две конструкции кода создают один и тот же код CLR?
Blake7
1
Одна из причин, по которой while (1) не работает, заключается в том, что он недействителен c #: test.cs (21,20): ошибка CS0031: постоянное значение '1' не может быть преобразовано в 'bool'
Blake7
1
Не на моей машине (win8.1, i5), всего около 20-30%, какой компьютер у вас был тогда? @SethSpearman
shinzou
17
Давайте немного повеселимся
using System;
using System.Timers;
namespace TimerExample{classProgram{staticTimer timer =newTimer(1000);staticint i =10;staticvoidMain(string[] args){
timer.Elapsed+=timer_Elapsed;
timer.Start();Console.Read();}privatestaticvoid timer_Elapsed(object sender,ElapsedEventArgs e){
i--;Console.Clear();Console.WriteLine("=================================================");Console.WriteLine(" DEFUSE THE BOMB");Console.WriteLine("");Console.WriteLine(" Time Remaining: "+ i.ToString());Console.WriteLine("");Console.WriteLine("=================================================");if(i ==0){Console.Clear();Console.WriteLine("");Console.WriteLine("==============================================");Console.WriteLine(" B O O O O O M M M M M ! ! ! !");Console.WriteLine("");Console.WriteLine(" G A M E O V E R");Console.WriteLine("==============================================");
timer.Close();
timer.Dispose();}
GC.Collect();}}}
очень нечитабельно и противоречит передовой практике. Это выглядит потрясающе, но не должно использоваться в продакшене, потому что некоторые люди будут гадить и какать сами.
Петр Кула
2
Reactive Extensions (Rx) не разрабатывался активно 2 года. Кроме того, примеры не имеют контекста и сбивают с толку. Мало знать диаграммы или примеры потоков.
Джеймс Бэйли,
4
Вы также можете использовать свои собственные механизмы синхронизации, если хотите немного большего контроля, но, возможно, меньшей точности и большего количества кода / сложности, но я все же рекомендую таймер. Однако используйте это, если вам нужно контролировать фактический поток синхронизации:
Если я хочу запустить пакетное задание до истечения времени ожидания, будет ли ваше предложение лучшим?
Йохан Бреслер,
1
Вы также можете создать свой собственный (если вас не устраивают доступные варианты).
Создание собственной Timerреализации - довольно простая вещь.
Это пример приложения, которому требовался доступ к COM-объекту в том же потоке, что и остальная часть моей кодовой базы.
/// <summary>/// Internal timer for window.setTimeout() and window.setInterval()./// This is to ensure that async calls always run on the same thread./// </summary>publicclassTimer:IDisposable{publicvoidTick(){if(Enabled&&Environment.TickCount>= nextTick){Callback.Invoke(this,null);
nextTick =Environment.TickCount+Interval;}}privateint nextTick =0;publicvoidStart(){this.Enabled=true;Interval= interval;}publicvoidStop(){this.Enabled=false;}publiceventEventHandlerCallback;publicboolEnabled=false;privateint interval =1000;publicintInterval{get{return interval;}set{ interval =value; nextTick =Environment.TickCount+ interval;}}publicvoidDispose(){this.Callback=null;this.Stop();}}
Чтобы убедиться, что таймер работает, вам нужно создать бесконечный цикл следующим образом:
while(true){// Create a new list in case a new timer// is added/removed during a callback.foreach(Timer timer innewList<Timer>(timers.Values)){
timer.Tick();}}
publicstaticvoidMain(){SetTimer();Console.WriteLine("\nPress the Enter key to exit the application...\n");Console.WriteLine("The application started at {0:HH:mm:ss.fff}",DateTime.Now);Console.ReadLine();
aTimer.Stop();
aTimer.Dispose();Console.WriteLine("Terminating the application...");}privatestaticvoidSetTimer(){// Create a timer with a two second interval.
aTimer =newSystem.Timers.Timer(2000);// Hook up the Elapsed event for the timer.
aTimer.Elapsed+=OnTimedEvent;
aTimer.AutoReset=true;
aTimer.Enabled=true;}privatestaticvoidOnTimedEvent(Object source,ElapsedEventArgs e){Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);}
Я сначала попробовал использовать System.Threading;с
var myTimer =newTimer((e)=>{// Code},null,TimeSpan.Zero,TimeSpan.FromSeconds(5));
но он постоянно останавливался примерно через 20 минут.
С этим я попробовал настройку решений
GC.KeepAlive(myTimer)
или
for(;;){}}
но в моем случае они не работали.
Следуя документации Microsoft, он работал отлично:
using System;
using System.Timers;publicclassExample{privatestaticTimer aTimer;publicstaticvoidMain(){// Create a timer and set a two second interval.
aTimer =newSystem.Timers.Timer();
aTimer.Interval=2000;// Hook up the Elapsed event for the timer.
aTimer.Elapsed+=OnTimedEvent;// Have the timer fire repeated events (true is the default)
aTimer.AutoReset=true;// Start the timer
aTimer.Enabled=true;Console.WriteLine("Press the Enter key to exit the program at any time... ");Console.ReadLine();}privatestaticvoidOnTimedEvent(Object source,System.Timers.ElapsedEventArgs e){Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);}}// The example displays output like the following: // Press the Enter key to exit the program at any time... // The Elapsed event was raised at 5/20/2015 8:48:58 PM // The Elapsed event was raised at 5/20/2015 8:49:00 PM // The Elapsed event was raised at 5/20/2015 8:49:02 PM // The Elapsed event was raised at 5/20/2015 8:49:04 PM // The Elapsed event was raised at 5/20/2015 8:49:06 PM
Ответы:
Это очень хорошо, однако для имитации прохождения некоторого времени нам нужно запустить команду, которая требует времени, и это очень ясно во втором примере.
Однако стиль использования цикла for для выполнения некоторых функций навсегда требует много ресурсов устройства, и вместо этого мы можем использовать сборщик мусора, чтобы делать что-то подобное.
Мы можем видеть эту модификацию в коде из той же книги CLR Via C # Third Ed.
источник
GC.Collect()
. Собирать нечего. Это имело бы смысл, если быGC.KeepAlive(t)
назвали послеConsole.ReadLine();
Используйте класс System.Threading.Timer.
System.Windows.Forms.Timer предназначен в первую очередь для использования в одном потоке, обычно это поток пользовательского интерфейса Windows Forms.
Существует также класс System.Timers, добавленный на ранних этапах разработки платформы .NET. Однако обычно рекомендуется использовать вместо него класс System.Threading.Timer, так как в любом случае это просто оболочка для System.Threading.Timer.
Также рекомендуется всегда использовать статический (общий в VB.NET) System.Threading.Timer, если вы разрабатываете службу Windows и вам требуется периодический запуск таймера. Это позволит избежать возможной преждевременной сборки мусора вашего объекта таймера.
Вот пример таймера в консольном приложении:
Из книги Джеффа Рихтера CLR Via C # . Между прочим, эта книга описывает обоснование трех типов таймеров в главе 23, настоятельно рекомендуется.
источник
Вот код для создания простого таймера на одну секунду:
И вот результат:
РЕДАКТИРОВАТЬ: никогда не рекомендуется добавлять жесткие циклы вращения в код, поскольку они потребляют циклы процессора без какой-либо выгоды. В этом случае этот цикл был добавлен только для того, чтобы остановить закрытие приложения, чтобы можно было наблюдать за действиями потока. Но для правильности и уменьшения загрузки ЦП в этот цикл был добавлен простой вызов режима сна.
источник
Давайте немного повеселимся
источник
Или с помощью Rx, коротко и мило:
источник
Вы также можете использовать свои собственные механизмы синхронизации, если хотите немного большего контроля, но, возможно, меньшей точности и большего количества кода / сложности, но я все же рекомендую таймер. Однако используйте это, если вам нужно контролировать фактический поток синхронизации:
будет вашим временным потоком (измените его, чтобы он останавливался при необходимости и в любом временном интервале, который вы хотите).
и для использования / запуска вы можете:
Обратный вызов - это ваш метод void без параметров, который вы хотите вызывать в каждом интервале. Например:
источник
Вы также можете создать свой собственный (если вас не устраивают доступные варианты).
Создание собственной
Timer
реализации - довольно простая вещь.Это пример приложения, которому требовался доступ к COM-объекту в том же потоке, что и остальная часть моей кодовой базы.
Вы можете добавлять события следующим образом:
Чтобы убедиться, что таймер работает, вам нужно создать бесконечный цикл следующим образом:
источник
В C # 5.0+ и .NET Framework 4.5+ вы можете использовать async / await:
источник
доктор
Вот и все :)
источник
Я предлагаю вам следовать рекомендациям Microsoft ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 ).
Я сначала попробовал использовать
System.Threading;
сно он постоянно останавливался примерно через 20 минут.
С этим я попробовал настройку решений
или
но в моем случае они не работали.
Следуя документации Microsoft, он работал отлично:
источник