System.Timers.Timer vs System.Threading.Timer

565

He estado revisando algunas de las posibles temporizadores últimamente, y System.Threading.Timery System.Timers.Timerson las que se ven necesaria para mí (ya que el apoyo conjunto de hilos).

Estoy haciendo un juego y planeo usar todo tipo de eventos, con diferentes intervalos, etc.

¿Cuál sería el mejor?

TheAJ
fuente

Respuestas:

363

Este artículo ofrece una explicación bastante completa:

" Comparación de las clases de temporizador en la biblioteca de clases de .NET Framework " - también disponible como un archivo .chm

La diferencia específica parece ser que System.Timers.Timerestá orientada a aplicaciones multiproceso y, por lo tanto, es segura para subprocesos a través de su SynchronizationObjectpropiedad, mientras que, System.Threading.Timerirónicamente, no es segura para subprocesos de fábrica.

No creo que haya una diferencia entre los dos en lo que respecta a cuán pequeños pueden ser sus intervalos.

David Andres
fuente
69
Creo que este extracto es esclarecedor: "A diferencia del System.Windows.Forms.Timer, la clase System.Timers.Timer, por defecto, llamará a su controlador de eventos del temporizador en un subproceso de trabajo obtenido del grupo de subprocesos de Common Language Runtime (CLR) . [...] La clase System.Timers.Timer proporciona una manera fácil de lidiar con este dilema: expone una propiedad pública SynchronizingObject. Establecer esta propiedad en una instancia de un formulario de Windows (o un control en un formulario de Windows) asegúrese de que el código en su controlador de eventos Elapsed se ejecute en el mismo subproceso en el que se ejecutó SynchronizingObject ".
mico
77
De acuerdo con la sección Seguridad de subprocesos en Threading.Timerel artículo de MSDN de MSDN , es perfectamente seguro para subprocesos ...
Pieter
6262
System.Threading.Timeres tan "irónicamente" no seguro para subprocesos como System.Threading.Threadlos subprocesos obtenidos a través del conjunto. El hecho de que estas clases no le den la mano y administren el uso de la lockpalabra clave en sí no significa que estas clases no sean seguras para subprocesos. También podría decir System.Threading.Threadque no es seguro para subprocesos, porque es exactamente igual de cierto.
Kirk Woll
8
También System.Timer.Timer intervalo solo puede ser Int32 System.Threading.Timer intervalo puede ser hasta Int64
Brent
11
Es lamentable que esta respuesta altamente engañosa (en el mejor de los casos) sea aceptada y tan altamente votada. La única declaración material en la respuesta en sí misma es simplemente incorrecta. El SynchronizingObjectno hace que el objeto del temporizador sea seguro para subprocesos. Solo se asegura de que su código para manejar el evento del temporizador se llame en un hilo específico (si configura esa propiedad adecuadamente). No se garantiza que el objeto del temporizador sea seguro para subprocesos, como se indica claramente en la documentación. Por otro lado, el System.Threading.Timerobjeto está específicamente documentado como seguro para subprocesos.
Peter Duniho el
169

System.Threading.TimerEs un simple temporizador. Le devuelve la llamada a un subproceso de grupo de subprocesos (del grupo de trabajo).

System.Timers.Timeres un System.ComponentModel.Componentque envuelve un System.Threading.Timer, y proporciona algunas características adicionales utilizadas para el envío en un hilo particular.

System.Windows.Forms.Timeren su lugar, envuelve un mensaje nativo solo HWND y usa temporizadores de ventana para generar eventos en ese bucle de mensajes HWND.

Si su aplicación no tiene interfaz de usuario y desea el temporizador .Net más liviano y de uso general posible (porque está contento de descubrir su propio enhebrado / despacho), entonces System.Threading.Timeres tan bueno como se obtiene en el marco.

No estoy completamente claro cuáles son los supuestos problemas de 'no es seguro para subprocesos' System.Threading.Timer. Quizás sea lo mismo que se hizo en esta pregunta: Seguridad de subprocesos de System.Timers.Timer vs System.Threading.Timer , o tal vez todo el mundo solo quiere decir que:

  1. es fácil escribir las condiciones de carrera cuando usas temporizadores. Por ejemplo, vea esta pregunta: Seguridad del hilo del temporizador (System.Threading)

  2. reencuentro de notificaciones de temporizador, donde su evento de temporizador puede activarse y devolverle la llamada por segunda vez antes de que termine de procesar el primer evento. Por ejemplo, vea esta pregunta: Ejecución segura para subprocesos utilizando System.Threading.Timer y Monitor

Tim Lovell-Smith
fuente
Es cierto que System.Timers.Timerutiliza System.Threading.Timerinternamente. Ver código fuente .
Stomy
120

En su libro " CLR Via C # ", Jeff Ritcher desalienta el uso de System.Timers.Timereste temporizador System.ComponentModel.Component, lo que permite su uso en la superficie de diseño de Visual Studio. De modo que solo sería útil si desea un temporizador en una superficie de diseño.

Prefiere utilizarlo System.Threading.Timerpara tareas en segundo plano en un subproceso de grupo de subprocesos.

Héroe
fuente
36
Se puede usar en una superficie de diseño, no significa que tenga que ser así, y no hay efectos perjudiciales por no hacerlo. Al leer el artículo en la respuesta anterior a esta pregunta, los Timers.Timer parecen mucho más preferibles que Threading.Timer.
Stephen Drew
66
Bueno, lo que es preferible depende del contexto, ¿verdad? Según tengo entendido, System.Threading.Timer ejecuta la devolución de llamada pasada en un nuevo subproceso de trabajo desde ThreadPool. Lo cual, supongo, es también por qué no es necesariamente seguro para subprocesos. Un poco tiene sentido. Entonces, en teoría, no tendría que preocuparse por el trabajo duro de girar su propio hilo de trabajo, ya que este temporizador lo hará por usted. Un poco parece ridículamente útil.
Finster
66
Usar System.Threading.Timeres similar a usar un grupo de hilos o crear su propio hilo. Por supuesto, estas clases no manejan la sincronización por usted , ¡ese es su trabajo! Ni un subproceso de grupo de subprocesos, su propio subproceso ni una devolución de llamada del temporizador manejarán el bloqueo: en qué objeto y de qué manera y en qué circunstancias necesita bloquear requiere un buen juicio y la versión de subprocesamiento del temporizador le brinda la mayor flexibilidad y granularidad
Kirk Woll
2
-1 esta respuesta es subjetiva u obvia desde el principio y no ofrece información concreta sobre por qué System.Threading.Timer es el preferido por Jeff Ritcher
Brian Ogden
42

Información de Microsoft sobre esto (ver Comentarios en MSDN ):

  • System.Timers.Timer , que activa un evento y ejecuta el código en uno o más receptores de eventos a intervalos regulares. La clase está diseñada para usarse como un componente de servicio o basado en servidor en un entorno multiproceso; no tiene interfaz de usuario y no es visible en tiempo de ejecución.
  • System.Threading.Timer , que ejecuta un único método de devolución de llamada en un subproceso de grupo de subprocesos a intervalos regulares. El método de devolución de llamada se define cuando se crea una instancia del temporizador y no se puede cambiar. Al igual que la clase System.Timers.Timer, esta clase está diseñada para usarse como un componente de servicio o basado en servidor en un entorno multiproceso; no tiene interfaz de usuario y no es visible en tiempo de ejecución.
  • System.Windows.Forms.Timer (solo .NET Framework), un componente de Windows Forms que activa un evento y ejecuta el código en uno o más receptores de eventos a intervalos regulares. El componente no tiene interfaz de usuario y está diseñado para su uso en un entorno de subproceso único; se ejecuta en el hilo de la interfaz de usuario.
  • System.Web.UI.Timer (solo .NET Framework), un componente ASP.NET que realiza devoluciones de página web asíncronas o síncronas a intervalos regulares.

Es interesante mencionar que System.Timers.Timerfue obsoleto con .NET Core 1.0, pero se implementó nuevamente en .NET Core 2.0 (/ .NET Standard 2.0). El objetivo con .NET Standard 2.0 era que debería ser lo más fácil posible cambiar de .NET Framework, que probablemente sea la razón por la que regresó.

Cuando quedó en desuso, el Complemento de .NET Portability Analyzer Visual Studio recomendó usar System.Threading.Timeren su lugar.

Parece que Microsoft favorece System.Threading.Timerantes System.Timers.Timer.

NOTA DE EDICIÓN 15/11/2018: entrego para cambiar mi respuesta ya que la información anterior sobre .NET Core 1.0 ya no era válida.

ice1e0
fuente
2
Parece que es verdad: github.com/npgsql/npgsql/issues/471#issuecomment-94104090
Marco Sulla
@Taegost, su uso también es limitado: consulte MSDN msdn.microsoft.com/en-us/library/… y lea los comentarios sobre la disponibilidad de la plataforma.
astrowalker
@astrowalker - Gracias por eso, en el momento en que hice el comentario, esta respuesta casi no tenía detalles. Como ahora tiene los detalles sobre los que estaba preguntando, eliminé mi comentario.
Taegost
1
System.Timers.Timer ahora es compatible con .NET Standard 2.0 y .NET Core 2.0 y versiones posteriores. docs.microsoft.com/en-us/dotnet/api/system.timers.timer (desplazarse hasta el final del artículo)
Lee Grissom
También hay System.Windows.Threading.DispatcherTimer por esta respuesta .
SpeedCoder5
39

Una diferencia importante no mencionada anteriormente que podría atraparte es que System.Timers.Timersilenciosamente traga excepciones, mientras System.Threading.Timerque no.

Por ejemplo:

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);
Stovroz
fuente
1
Recientemente toqué este problema con Timers.Timer y ha sido muy doloroso ... ¿Alguna idea de cómo podría volver a escribir con Threading.Timer? stackoverflow.com/questions/41618324/…
Tez Wingfield
77
Hay una captura vacía en el código fuente. Vea el código fuente de System.Timers.Timer aquí
stomy
Omgsh, ¿por qué los programadores de MS no pueden hacer lo mismo realmente?
xmedeko
2
El ejemplo no explica cómo uno se traga las excepciones y el otro no. ¿Podría alguien completar los detalles?
sean
24

Encontré una breve comparación de MSDN

.NET Framework Class Library incluye cuatro clases llamadas Timer, cada una de las cuales ofrece una funcionalidad diferente:

System.Timers.Timer, que activa un evento y ejecuta el código en uno o más receptores de eventos a intervalos regulares. La clase está diseñada para usarse como un componente de servicio o basado en servidor en un entorno multiproceso; no tiene interfaz de usuario y no es visible en tiempo de ejecución.

System.Threading.Timer, que ejecuta un único método de devolución de llamada en un subproceso de grupo de subprocesos a intervalos regulares. El método de devolución de llamada se define cuando se crea una instancia del temporizador y no se puede cambiar. Al igual que la clase System.Timers.Timer, esta clase está diseñada para usarse como un componente de servicio o basado en servidor en un entorno multiproceso; no tiene interfaz de usuario y no es visible en tiempo de ejecución.

System.Windows.Forms.Timer, un componente de Windows Forms que dispara un evento y ejecuta el código en uno o más receptores de eventos a intervalos regulares. El componente no tiene interfaz de usuario y está diseñado para su uso en un entorno de subproceso único.

System.Web.UI.Timer, un componente ASP.NET que realiza devoluciones de datos asíncronas o síncronas de páginas web a intervalos regulares.

Defecto
fuente
1

Las dos clases son funcionalmente equivalentes, excepto que System.Timers.Timertiene una opción para invocar todas sus devoluciones de llamada de caducidad del temporizador a través de ISynchronizeInvoke configurando SynchronizingObject . De lo contrario, ambos temporizadores invocan devoluciones de llamada de vencimiento en subprocesos de grupo de subprocesos.

Cuando arrastra un objeto System.Timers.Timera una superficie de diseño de formularios Windows Forms, Visual Studio establece SynchronizingObject en el objeto formulario, lo que provoca que todas las devoluciones de llamada de vencimiento se invoquen en el subproceso de la interfaz de usuario.

Edward Brey
fuente
1

Desde MSDN: System.Threading.Timeres un temporizador simple y liviano que utiliza métodos de devolución de llamada y es atendido por subprocesos de grupo de subprocesos. No se recomienda su uso con Windows Forms, ya que sus devoluciones de llamada no se producen en el hilo de la interfaz de usuario. System.Windows.Forms.Timeres una mejor opción para usar con Windows Forms. Para la funcionalidad del temporizador basado en el servidor, puede considerar el uso System.Timers.Timer, que genera eventos y tiene características adicionales.

Fuente

Greg Gum
fuente