System.Timers.Timer vs System.Threading.Timer


565

Ultimamente, tenho verificado alguns dos possíveis temporizadores System.Threading.Timere System.Timers.Timersão os que me parecem mais necessários (já que eles oferecem suporte ao pool de threads).

Estou fazendo um jogo e planejo usar todos os tipos de eventos, com intervalos diferentes, etc.

Qual seria o melhor?

Respostas:


363

Este artigo oferece uma explicação bastante abrangente:

" Comparando as classes de timer na biblioteca de classes do .NET Framework " - também disponível como um arquivo .chm

A diferença específica parece ser System.Timers.Timervoltada para aplicativos multithread e, portanto, é segura para threads por meio de sua SynchronizationObjectpropriedade, enquanto que, System.Threading.Timerironicamente, não é segura para threads, pronta para uso.

Não acredito que exista uma diferença entre os dois, no que diz respeito ao tamanho dos seus intervalos.


69
Acho que esse trecho é esclarecedor: "Diferentemente da System.Windows.Forms.Timer, a classe System.Timers.Timer, por padrão, chama seu manipulador de eventos de timer em um thread de trabalho obtido do pool de threads do Common Language Runtime (CLR) [...] A classe System.Timers.Timer fornece uma maneira fácil de lidar com esse dilema - ela expõe uma propriedade pública SynchronizingObject.A definição dessa propriedade a uma instância de um Windows Form (ou a um controle em um Windows Form) verifique se o código no manipulador de eventos decorrido é executado no mesmo encadeamento no qual o SynchronizingObject foi instanciado. "
Mico

7
De acordo com a seção de Segurança de thread em Threading.Timer's artigo MSDN , é perfeitamente thread-safe ...
Pieter

62
System.Threading.Timeré "ironicamente" não seguro para System.Threading.Threadthreads e os threads obtidos através do pool. Só porque essas classes não seguram sua mão e gerenciam o uso da lockpalavra-chave em si, não significa que essas classes não sejam seguras. Você também pode dizer que System.Threading.Threadnão é seguro para threads, porque é exatamente tão verdadeiro.
Kirk Woll

8
Além disso, o intervalo System.Timer.Timer pode ser apenas Int32 O intervalo System.Threading.Timer pode ser até Int64
Brent

11
É lamentável que esta resposta altamente enganadora (na melhor das hipóteses) seja aceita e recebida com alta aprovação. A única declaração material na resposta em si é simplesmente errada. A SynchronizingObjectnão faz o próprio objeto temporizador thread-safe. Apenas garante que o seu código para manipular o evento do timer seja chamado em um thread específico (se você definir essa propriedade adequadamente). O próprio objeto timer não garante a segurança de threads, conforme claramente indicado na documentação. Por outro lado, o System.Threading.Timerobjeto é documentado especificamente como seguro para threads.
precisa saber é o seguinte

169

System.Threading.Timeré um cronômetro simples. Ele chama você de volta em um thread do conjunto de threads (do pool de trabalho).

System.Timers.Timeré um System.ComponentModel.Componentque envolve ae System.Threading.Timerfornece alguns recursos adicionais usados ​​para despachar em um encadeamento específico.

System.Windows.Forms.Timerem vez disso, agrupa um HWND somente mensagem nativo e usa Temporizadores de Janela para gerar eventos nesse loop de mensagem HWNDs.

Se o seu aplicativo não tiver uma interface do usuário e você desejar o temporizador .Net mais leve e de uso geral possível (porque você está feliz em descobrir seu próprio encadeamento / envio), então System.Threading.Timeré o melhor possível na estrutura.

Não estou totalmente claro com o que os supostos problemas "não são seguros para tópicos" System.Threading.Timer. Talvez seja exatamente o mesmo feito nesta pergunta: Segurança de thread de System.Timers.Timer vs System.Threading.Timer , ou talvez todo mundo apenas queira dizer:

  1. é fácil escrever condições de corrida quando você usa temporizadores. Por exemplo, veja esta pergunta: Segurança de encadeamento do temporizador (System.Threading)

  2. re-entrada de notificações de timer, em que seu evento de timer pode ser acionado e retornar uma segunda vez antes de terminar o processamento do primeiro evento. Por exemplo, veja esta pergunta: Execução segura de threads usando System.Threading.Timer e Monitor


Verdadeiro System.Timers.Timerusa um System.Threading.Timerinternamente. Veja o código fonte .
Stom

120

Em seu livro " CLR Via C # ", Jeff Ritcher desencoraja o uso System.Timers.Timer, a partir desse timer System.ComponentModel.Component, permitindo que ele seja usado na superfície de design do Visual Studio. Para que seja útil apenas se você quiser um cronômetro em uma superfície de design.

Ele prefere usar System.Threading.Timerpara tarefas em segundo plano em um thread do conjunto de threads.


36
Ele pode ser usado em uma superfície de design - não significa que precisa ser, e não há efeitos prejudiciais por não fazer isso. Lendo o artigo na resposta anterior a essa pergunta, o Timers.Timer parece muito mais preferível ao Threading.Timer.
Stephen Drew

6
Bem, o que é preferível depende do contexto, certo? Pelo que entendi, System.Threading.Timer executa o retorno de chamada passado em um novo thread de trabalho do ThreadPool. O que, suponho, também é por isso que não é necessariamente seguro para threads. Meio que faz sentido. Portanto, em teoria, você não precisaria se preocupar com o trabalho duro de criar seu próprio segmento de trabalho, pois esse temporizador fará isso por você. Meio que parece ridiculamente útil.
Finster 27/03

6
Usar System.Threading.Timeré semelhante a usar um pool de threads ou criar seu próprio thread. É claro que essas classes não tratam da sincronização para você - esse é o seu trabalho! Nem um segmento de pool de encadeamentos, seu próprio encadeamento nem um retorno de chamada do temporizador manipularão o bloqueio - em qual objeto, de que maneira e em que circunstâncias você precisa bloquear exige um bom julgamento, e a versão de encadeamento do temporizador oferece mais flexibilidade e granularidade.
precisa

2
-1 esta resposta é subjetiva ou opinativo desde o início e não oferece informações concretas sobre o porquê System.Threading.Timer é preferido por Jeff Ritcher
Brian Ogden

42

Informações da Microsoft sobre isso (consulte Comentários no MSDN ):

  • System.Timers.Timer , que dispara um evento e executa o código em um ou mais coletores de eventos em intervalos regulares. A classe é destinada ao uso como um componente de serviço ou baseado em servidor em um ambiente multithread; não possui interface com o usuário e não é visível em tempo de execução.
  • System.Threading.Timer , que executa um único método de retorno de chamada em um thread do conjunto de threads em intervalos regulares. O método de retorno de chamada é definido quando o timer é instanciado e não pode ser alterado. Como a classe System.Timers.Timer, essa classe é destinada ao uso como um componente de serviço ou baseado em servidor em um ambiente multithread; não possui interface com o usuário e não é visível em tempo de execução.
  • System.Windows.Forms.Timer (somente .NET Framework), um componente do Windows Forms que dispara um evento e executa o código em um ou mais coletores de eventos em intervalos regulares. O componente não possui interface com o usuário e foi projetado para uso em um ambiente de thread único; ele é executado no thread da interface do usuário.
  • System.Web.UI.Timer (somente .NET Framework), um componente do ASP.NET que executa postagens assíncronas ou síncronas de páginas da Web em intervalos regulares.

É interessante mencionar que System.Timers.Timerfoi preterido no .NET Core 1.0, mas foi implementado novamente no .NET Core 2.0 (/ .NET Standard 2.0). O objetivo do .NET Standard 2.0 era que fosse o mais fácil possível alternar do .NET Framework, provavelmente o motivo pelo qual ele voltou.

Quando foi preterido, o Suplemento do Visual Studio do .NET Portability Analyzer recomendou o uso System.Threading.Timer.

Parece que a Microsoft prefere System.Threading.Timerantes System.Timers.Timer.

NOTA DE EDIÇÃO 2018-11-15: entrego para alterar minha resposta, pois as informações antigas sobre o .NET Core 1.0 não eram mais válidas.



@ Taegost, seu uso também é limitado - consulte MSDN msdn.microsoft.com/en-us/library/… e leia as observações sobre a disponibilidade da plataforma.
Astrowalker

@astrowalker - Obrigado por isso, no momento em que fiz o comentário, essa resposta quase não tinha detalhes. Como agora ele tem os detalhes que eu estava perguntando, excluí meu comentário.
Taegost

1
Agora System.Timers.Timer agora é suportado no .NET Standard 2.0 e .NET Core 2.0 e superior. docs.microsoft.com/en-us/dotnet/api/system.timers.timer (rolagem para o final do artigo)
Lee Grissom


39

Uma diferença importante não mencionada acima, que pode surpreendê-lo, é que System.Timers.Timersilenciosamente engole exceções, enquanto System.Threading.Timerque não.

Por exemplo:

var timer = new System.Timers.Timer { AutoReset = false };
timer.Elapsed += (sender, args) =>
{
    var z = 0;
    var i = 1 / z;
};
timer.Start();

vs

var timer = new System.Threading.Timer(x =>
{
    var z = 0;
    var i = 1 / z;
}, null, 0, Timeout.Infinite);

1
Recentemente, bati esse problema com o Timers.Timer e tem sido muito doloroso ... Alguma idéia de como eu poderia reescrever com o Threading.Timer? stackoverflow.com/questions/41618324/...
Tez Wingfield

7
Há uma captura vazia no código fonte. Veja o código fonte System.Timers.Timer aqui
stomy

Omgsh por que os programadores da MS não são capazes de fazer as mesmas coisas realmente iguais?
Xmedeko 16/05/19

2
O exemplo não explica como um engole exceções e o outro não. Alguém poderia preencher os detalhes?
Sean

24

Encontrei uma pequena comparação no MSDN

A .NET Framework Class Library inclui quatro classes nomeadas Timer, cada uma das quais oferece funcionalidade diferente:

System.Timers.Timer, que dispara um evento e executa o código em um ou mais coletores de eventos em intervalos regulares. A classe é destinada ao uso como um componente de serviço ou baseado em servidor em um ambiente multithread; não possui interface com o usuário e não é visível em tempo de execução.

System.Threading.Timer, que executa um único método de retorno de chamada em um thread do conjunto de threads em intervalos regulares. O método de retorno de chamada é definido quando o timer é instanciado e não pode ser alterado. Como a classe System.Timers.Timer, essa classe é destinada ao uso como um componente de serviço ou baseado em servidor em um ambiente multithread; não possui interface com o usuário e não é visível em tempo de execução.

System.Windows.Forms.Timer, um componente do Windows Forms que dispara um evento e executa o código em um ou mais coletores de eventos em intervalos regulares. O componente não possui interface com o usuário e foi projetado para uso em um ambiente de thread único.

System.Web.UI.Timer, um componente do ASP.NET que executa postagens assíncronas ou síncronas de páginas da Web em intervalos regulares.


1

As duas classes são funcionalmente equivalentes, exceto que System.Timers.Timertem uma opção para chamar todos os retornos de chamada de expiração do timer através do ISynchronizeInvoke , definindo SynchronizingObject . Caso contrário, os dois timers invocam retornos de chamada de expiração nos threads do conjunto de threads.

Quando você arrasta um System.Timers.Timerpara uma superfície de design do Windows Forms, o Visual Studio define SynchronizingObject para o objeto de formulário, o que faz com que todos os retornos de chamada de expiração sejam chamados no thread da interface do usuário.


1

Do MSDN: System.Threading.Timeré um timer simples e leve que usa métodos de retorno de chamada e é atendido por threads do pool de threads. Não é recomendado para uso com o Windows Forms, porque seus retornos de chamada não ocorrem no thread da interface do usuário. System.Windows.Forms.Timeré uma escolha melhor para uso com o Windows Forms. Para a funcionalidade de timer baseado em servidor, você pode considerar o uso System.Timers.Timer, o que gera eventos e possui recursos adicionais.

Fonte

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.