Cuidado: as respostas aqui têm um erro, o objeto Timer será coletado como lixo. A referência ao cronômetro deve ser armazenada em uma variável estática para garantir que ele continue funcionando.
Hans Passant
@HansPassant Parece que você perdeu a declaração clara na minha resposta: "Também é recomendável usar sempre um System.Threading.Timer estático (compartilhado no VB.NET) se você estiver desenvolvendo um serviço do Windows e precisar de um timer para executar periodicamente. Isso evitará a coleta de lixo possivelmente prematura do seu objeto timer. " Se as pessoas querem copiar um exemplo aleatório e usá-lo às cegas, é problema deles.
Ash
Respostas:
120
Isso é muito bom, no entanto, para simular algum tempo, precisamos executar um comando que leva algum tempo e isso é muito claro no segundo exemplo.
No entanto, o estilo de usar um loop for para executar algumas funcionalidades sempre exige muitos recursos do dispositivo. Em vez disso, podemos usar o Garbage Collector para fazer algo assim.
Podemos ver essa modificação no código do mesmo livro 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();}}
Khalid, isso foi extremamente útil. Obrigado. O console.readline () e o GC.Collect eram exatamente o que eu precisava.
Seth Spearman
9
@ Ralph Willgoss, Por que GC.Collect (); É necessário?
Puchacz
2
@Puchacz Não vejo razão para ligar GC.Collect(). Não há nada a cobrar. Faria sentido, se GC.KeepAlive(t)fosse chamado depoisConsole.ReadLine();
newprint
1
Terminou após o primeiro retorno de chamada
BadPiggie 18/09/18
1
@Khalid Al Hajami "No entanto, o estilo de usar um loop for para executar alguma funcionalidade requer sempre muitos recursos do dispositivo. Em vez disso, podemos usar o Garbage Collector para fazer algo assim." Isso é um absurdo absurdo. O coletor de lixo é totalmente irrelevante. Você copiou isso de um livro e não entendeu o que estava copiando?
Ash
65
Use a classe System.Threading.Timer.
System.Windows.Forms.Timer foi projetado principalmente para uso em um único thread, geralmente o thread da UI do Windows Forms.
Há também uma classe System.Timers adicionada no início do desenvolvimento da estrutura .NET. No entanto, geralmente é recomendável usar a classe System.Threading.Timer, pois isso é apenas um invólucro em torno de System.Threading.Timer de qualquer maneira.
Também é recomendável usar sempre um System.Threading.Timer estático (compartilhado no VB.NET) se você estiver desenvolvendo um Serviço do Windows e precisar de um timer para executar periodicamente. Isso evitará a coleta de lixo possivelmente prematura do seu objeto de timer.
Aqui está um exemplo de um timer em um aplicativo de console:
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 }}
Do livro CLR Via C # de Jeff Richter. A propósito, este livro descreve a lógica por trás dos 3 tipos de temporizadores no Capítulo 23, altamente recomendados.
Eric, eu não tentei, mas não seria incomum se houvesse um problema. Percebo que ele também está tentando fazer algum tipo de sincronização entre threads, essa também é uma área que pode ser complicada de acertar. Se você pode evitá-lo em seu design, é sempre inteligente fazer isso.
Ash
1
Ash - Eu definitivamente concordo com exemplos de msdn. Porém, eu não descartaria imediatamente o código de sincronização, se o temporizador for executado em seu próprio encadeamento, você estará escrevendo um aplicativo com vários encadeamentos e precisará estar ciente dos problemas relacionados à sincronização.
Eric Tuttleman 9/10/08
1
O que acontece se houver vários métodos que correspondam à assinatura do representante TimerCallback?
Ozkan
22
Aqui está o código para criar um simples temporizador de um segundo:
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);}}}
EDIT: nunca é uma boa idéia adicionar loops de rotação rígidos no código, pois eles consomem ciclos da CPU sem nenhum ganho. Nesse caso, esse loop foi adicionado apenas para impedir o fechamento do aplicativo, permitindo que as ações do thread fossem observadas. Mas, por uma questão de correção e para reduzir o uso da CPU, uma simples chamada de suspensão foi adicionada a esse loop.
Não é óbvio que se você tiver um loop for infinito, isso resultará em uma CPU de 100%. Para corrigir isso, tudo o que você precisa fazer é adicionar uma chamada de suspensão ao loop.
veight
3
É incrível quantas pessoas estão concentradas em saber se o loop for deve ser um while e por que a CPU chega a 100%. Falar sobre perder a madeira para as árvores! Azimute, eu pessoalmente gostaria de saber como um tempo (1) seria diferente do loop for infinito? Certamente as pessoas que escrevem o otimizador do compilador CLR garantirão que essas duas construções de código criem exatamente o mesmo código CLR?
Blake7
1
Uma razão pela qual while (1) não vai funcionar é que não é válido c #: test.cs (21,20): CS0031 de erro: Valor constante '1' não pode ser convertido para um 'bool'
Blake7
1
Não na minha máquina (win8.1, i5), apenas cerca de 20 a 30%, que tipo de computador você tinha naquela época? @SethSpearman
shinzou
17
Vamos nos divertir um pouco
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();}}}
ilegível e contra as melhores práticas. Parece incrível, mas não deve ser usado na produção, porque algumas pessoas vão pesar e cocô.
Piotr Kula
2
As Extensões Reativas (Rx) não são desenvolvidas ativamente há 2 anos. Além disso, os exemplos são sem contexto e confusos. Pouco para saber diagramas ou exemplos de fluxo.
James Bailey
4
Você também pode usar seus próprios mecanismos de tempo, se quiser um pouco mais de controle, mas possivelmente menos precisão e mais código / complexidade, mas eu ainda recomendaria um timer. Use isso se precisar ter controle sobre o encadeamento de tempo real:
Se eu quiser executar um trabalho em lotes até o tempo limite expirar, sua sugestão aqui será a melhor?
Johan Bresler 9/10/08
1
Você também pode criar o seu próprio (se não estiver satisfeito com as opções disponíveis).
Criar sua própria Timerimplementação é algo bastante básico.
Este é um exemplo para um aplicativo que precisava de acesso a objetos COM no mesmo thread que o restante da minha base de código.
/// <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();}}
Para garantir que o timer funcione, é necessário criar um loop infinito da seguinte maneira:
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);}
var myTimer =newTimer((e)=>{// Code},null,TimeSpan.Zero,TimeSpan.FromSeconds(5));
mas parou continuamente após ~ 20 minutos.
Com isso, tentei a configuração de soluções
GC.KeepAlive(myTimer)
ou
for(;;){}}
mas eles não funcionaram no meu caso.
Após a documentação da Microsoft, funcionou perfeitamente:
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
Respostas:
Isso é muito bom, no entanto, para simular algum tempo, precisamos executar um comando que leva algum tempo e isso é muito claro no segundo exemplo.
No entanto, o estilo de usar um loop for para executar algumas funcionalidades sempre exige muitos recursos do dispositivo. Em vez disso, podemos usar o Garbage Collector para fazer algo assim.
Podemos ver essa modificação no código do mesmo livro CLR Via C # Third Ed.
fonte
GC.Collect()
. Não há nada a cobrar. Faria sentido, seGC.KeepAlive(t)
fosse chamado depoisConsole.ReadLine();
Use a classe System.Threading.Timer.
System.Windows.Forms.Timer foi projetado principalmente para uso em um único thread, geralmente o thread da UI do Windows Forms.
Há também uma classe System.Timers adicionada no início do desenvolvimento da estrutura .NET. No entanto, geralmente é recomendável usar a classe System.Threading.Timer, pois isso é apenas um invólucro em torno de System.Threading.Timer de qualquer maneira.
Também é recomendável usar sempre um System.Threading.Timer estático (compartilhado no VB.NET) se você estiver desenvolvendo um Serviço do Windows e precisar de um timer para executar periodicamente. Isso evitará a coleta de lixo possivelmente prematura do seu objeto de timer.
Aqui está um exemplo de um timer em um aplicativo de console:
Do livro CLR Via C # de Jeff Richter. A propósito, este livro descreve a lógica por trás dos 3 tipos de temporizadores no Capítulo 23, altamente recomendados.
fonte
Aqui está o código para criar um simples temporizador de um segundo:
E aqui está a saída resultante:
EDIT: nunca é uma boa idéia adicionar loops de rotação rígidos no código, pois eles consomem ciclos da CPU sem nenhum ganho. Nesse caso, esse loop foi adicionado apenas para impedir o fechamento do aplicativo, permitindo que as ações do thread fossem observadas. Mas, por uma questão de correção e para reduzir o uso da CPU, uma simples chamada de suspensão foi adicionada a esse loop.
fonte
Vamos nos divertir um pouco
fonte
Ou usando Rx, curto e doce:
fonte
Você também pode usar seus próprios mecanismos de tempo, se quiser um pouco mais de controle, mas possivelmente menos precisão e mais código / complexidade, mas eu ainda recomendaria um timer. Use isso se precisar ter controle sobre o encadeamento de tempo real:
seria seu encadeamento de tempo (modifique-o para parar quando necessário, e no intervalo de tempo que você desejar).
e para usar / iniciar, você pode fazer:
O retorno de chamada é o método nulo e sem parâmetros que você deseja chamar a cada intervalo. Por exemplo:
fonte
Você também pode criar o seu próprio (se não estiver satisfeito com as opções disponíveis).
Criar sua própria
Timer
implementação é algo bastante básico.Este é um exemplo para um aplicativo que precisava de acesso a objetos COM no mesmo thread que o restante da minha base de código.
Você pode adicionar eventos da seguinte maneira:
Para garantir que o timer funcione, é necessário criar um loop infinito da seguinte maneira:
fonte
No C # 5.0+ e no .NET Framework 4.5+, você pode usar async / waitit:
fonte
doc
Aí está :)
fonte
Sugiro que você siga as diretrizes da Microsoft ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 ).
Eu tentei usar
System.Threading;
commas parou continuamente após ~ 20 minutos.
Com isso, tentei a configuração de soluções
ou
mas eles não funcionaram no meu caso.
Após a documentação da Microsoft, funcionou perfeitamente:
fonte