System.Timers.Timer vs System.Threading.Timer


565

Ultimamente ho verificato alcuni dei possibili timer System.Threading.Timere System.Timers.Timersono quelli che mi sembrano necessari (poiché supportano il pool di thread).

Sto realizzando un gioco e intendo utilizzare tutti i tipi di eventi, con intervalli diversi, ecc.

Quale sarebbe il migliore?

Risposte:


363

Questo articolo offre una spiegazione abbastanza completa:

" Confronto delle classi timer nella libreria di classi .NET Framework " - disponibile anche come file .chm

La differenza specifica sembra essere System.Timers.Timerorientata verso applicazioni multithread ed è quindi sicura per i thread grazie alle sue SynchronizationObjectproprietà, mentre System.Threading.Timerironicamente non è pronta all'uso per i thread.

Non credo che ci sia una differenza tra i due in quanto riguarda quanto piccoli possano essere i tuoi intervalli.


69
Penso che questo estratto sia illuminante: "A differenza del System.Windows.Forms.Timer, la classe System.Timers.Timer chiamerà, per impostazione predefinita, il gestore eventi timer su un thread di lavoro ottenuto dal pool di thread Common Language Runtime (CLR) . [...] La classe System.Timers.Timer fornisce un modo semplice per affrontare questo dilemma: espone una proprietà pubblica SynchronizingObject. L'impostazione di questa proprietà su un'istanza di un Windows Form (o un controllo su un Windows Form) assicurarsi che il codice nel gestore dell'evento trascorso sia eseguito sullo stesso thread su cui è stata istanziata SynchronizingObject. "
mico,

7
Secondo la sezione di filo di sicurezza in Threading.Timer's articolo di MSDN , è perfettamente thread-safe ...
Pieter

62
System.Threading.Timer"ironicamente" non è sicuro come System.Threading.Threadi thread e i thread ottenuti attraverso il pool. Solo perché queste classi non ti tengono per mano e gestiscono l'uso della lockparola chiave stessa non significa che queste classi non siano thread-safe. Potresti anche dire che System.Threading.Threadnon è sicuro, perché è esattamente vero.
Kirk Woll,

8
Anche l'intervallo System.Timer.Timer può essere solo Int32 System.Threading.L'intervallo timer può essere fino a Int64
Brent

11
È un peccato che questa risposta altamente fuorviante (nella migliore delle ipotesi) sia accettata e così fortemente votata. L'unica affermazione materiale nella risposta stessa è semplicemente sbagliata. Il SynchronizingObjectnon rende l'oggetto timer stesso thread-safe. Si assicura solo che il codice per gestire l'evento timer venga chiamato in un thread specifico (se si imposta tale proprietà in modo appropriato). L'oggetto timer stesso non è garantito come thread-safe, come chiaramente indicato nella documentazione. D'altra parte, l' System.Threading.Timeroggetto è specificamente documentato come thread-safe.
Peter Duniho,

169

System.Threading.Timerè un semplice timer. Richiama un thread del pool di thread (dal pool di lavoro).

System.Timers.Timerè un a System.ComponentModel.Componentche avvolge a System.Threading.Timere fornisce alcune funzionalità aggiuntive utilizzate per l'invio su un thread specifico.

System.Windows.Forms.Timeravvolge invece un HWND nativo solo per messaggi e utilizza i timer finestra per generare eventi in quel ciclo di messaggi HWND.

Se la tua app non ha un'interfaccia utente e desideri il timer .Net più leggero e generico, (perché sei felice di capire il tuo threading / invio), allora System.Threading.Timerè buono come si ottiene nel framework.

Non sono del tutto chiaro quali siano i presunti problemi "non thread-safe" System.Threading.Timer. Forse è esattamente lo stesso di questa domanda: thread-safety di System.Timers.Timer vs System.Threading.Timer , o forse tutti significano semplicemente che:

  1. è facile scrivere le condizioni di gara quando si utilizzano i timer. Ad esempio, vedi questa domanda: Timer (System.Threading) sicurezza thread

  2. reinserimento delle notifiche timer, in cui l'evento timer può attivarsi e richiamarti una seconda volta prima di completare l'elaborazione del primo evento. Ad esempio, vedere questa domanda: esecuzione thread-safe utilizzando System.Threading.Timer e Monitor


È vero System.Timers.Timerutilizza System.Threading.Timerinternamente. Vedi il codice sorgente .
ventre

120

Nel suo libro " CLR Via C # ", Jeff Ritcher scoraggia l'utilizzo System.Timers.Timer, questo timer è derivato System.ComponentModel.Component, permettendogli di essere utilizzato nella superficie di progettazione di Visual Studio. In modo che sarebbe utile solo se si desidera un timer su una superficie di progettazione.

Preferisce utilizzare le System.Threading.Timerattività in background su un thread del pool di thread.


36
Può essere utilizzato in una superficie di progettazione - non significa che debba esserlo e non ci sono effetti dannosi nel non farlo. Leggendo l'articolo nella risposta precedente a questa domanda, Timers.Timer sembra molto più preferibile a Threading.Timer.
Stephen Drew,

6
Bene, ciò che è preferibile dipende dal contesto, giusto? A quanto ho capito, System.Threading.Timer esegue il callback passato su un nuovo thread di lavoro da ThreadPool. Il che, presumo, è anche il motivo per cui non è necessariamente thread-safe. Kinda ha un senso. Quindi, in teoria, non dovresti preoccuparti del grugnito di far girare il tuo thread di lavoro, poiché questo timer lo farà per te. Kinda sembra ridicolmente utile.
Finster,

6
L'uso System.Threading.Timerè simile all'utilizzo di un pool di thread o alla creazione del proprio thread. Di Naturalmente queste classi non gestiscono la sincronizzazione per voi - che è il tuo lavoro! Né un thread del pool di thread, il proprio thread né un callback del timer gestiranno il blocco: su quale oggetto, in che modo e in quali circostanze è necessario bloccare richiede un buon giudizio e la versione di threading del timer offre la massima flessibilità e granularità.
Kirk Woll,

2
-1 questa risposta è soggettiva o supponente fin dall'inizio e non offre informazioni concrete sul perché System.Threading.Timer è preferito da Jeff Ritcher
Brian Ogden,

42

Informazioni da Microsoft su questo (vedi Note su MSDN ):

  • System.Timers.Timer , che genera un evento ed esegue il codice in uno o più sink di evento a intervalli regolari. La classe è destinata all'uso come componente basato su server o di servizio in un ambiente multithread; non ha un'interfaccia utente e non è visibile in fase di esecuzione.
  • System.Threading.Timer , che esegue un singolo metodo di callback su un thread del pool di thread a intervalli regolari. Il metodo di callback è definito quando il timer è istanziato e non può essere modificato. Come la classe System.Timers.Timer, questa classe è destinata all'uso come componente basato su server o di servizio in un ambiente multithread; non ha un'interfaccia utente e non è visibile in fase di esecuzione.
  • System.Windows.Forms.Timer (solo .NET Framework), un componente di Windows Form che genera un evento ed esegue il codice in uno o più sink di evento a intervalli regolari. Il componente non ha un'interfaccia utente ed è progettato per l'uso in un ambiente a thread singolo; viene eseguito sul thread dell'interfaccia utente.
  • System.Web.UI.Timer (solo .NET Framework), un componente ASP.NET che esegue postback asincroni o sincroni delle pagine Web a intervalli regolari.

È interessante ricordare che è System.Timers.Timerstato deprecato con .NET Core 1.0, ma è stato nuovamente implementato in .NET Core 2.0 (/ .NET Standard 2.0). L'obiettivo con .NET Standard 2.0 era che dovrebbe essere il più semplice possibile passare da .NET Framework, che probabilmente è la ragione per cui è tornato.

Quando è stato deprecato, si consiglia di utilizzare invece il componente aggiuntivo .NET Studio di portabilità di Visual StudioSystem.Threading.Timer .

Sembra che Microsoft preferisca System.Threading.Timerprima System.Timers.Timer.

NOTA EDIT: 15-11-2018: passo a cambiare la mia risposta poiché le vecchie informazioni su .NET Core 1.0 non erano più valide.



@Taegost, anche il suo utilizzo è limitato - vedi MSDN msdn.microsoft.com/en-us/library/… e leggi le osservazioni sulla disponibilità della piattaforma.
astrowalker,

@astrowalker - Grazie per quello, al momento in cui ho fatto il commento questa risposta non aveva quasi alcun dettaglio. Dato che ora ha i dettagli di cui mi stavo chiedendo, ho eliminato il mio commento.
Taegost,

1
System.Timers.Timer è ora supportato in .NET Standard 2.0 e .NET Core 2.0 e versioni successive. docs.microsoft.com/en-us/dotnet/api/system.timers.timer (scorrere fino alla fine dell'articolo)
Lee Grissom,


39

Una differenza importante non menzionata sopra che potrebbe sorprenderti è che System.Timers.Timeringoia silenziosamente le eccezioni, mentre System.Threading.Timernon lo fa.

Per esempio:

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
Di recente ho riscontrato questo problema con Timers.Timer ed è stato molto doloroso ... Qualche idea su come riscrivere con Threading.Timer? stackoverflow.com/questions/41618324/…
Tez Wingfield

7
C'è un fermo vuoto nel codice sorgente. Vedi il codice sorgente System.Timers.Timer qui
stomy

Omgsh, perché i programmatori MS non sono in grado di fare le stesse cose davvero allo stesso modo?
xmedeko,

2
L'esempio non spiega come uno ingoia le eccezioni e l'altro no. Qualcuno potrebbe compilare i dettagli?
sean,

24

Ho trovato un breve confronto da MSDN

La libreria di classi .NET Framework include quattro classi denominate Timer, ognuna delle quali offre funzionalità diverse:

System.Timers.Timer, che genera un evento ed esegue il codice in uno o più sink di evento a intervalli regolari. La classe è destinata all'uso come componente basato su server o di servizio in un ambiente multithread; non ha un'interfaccia utente e non è visibile in fase di esecuzione.

System.Threading.Timer, che esegue un singolo metodo di callback su un thread del pool di thread a intervalli regolari. Il metodo di callback è definito quando il timer è istanziato e non può essere modificato. Come la classe System.Timers.Timer, questa classe è destinata all'uso come componente basato su server o di servizio in un ambiente multithread; non ha un'interfaccia utente e non è visibile in fase di esecuzione.

System.Windows.Forms.Timer, un componente di Windows Form che genera un evento ed esegue il codice in uno o più sink di evento a intervalli regolari. Il componente non ha un'interfaccia utente ed è progettato per l'uso in un ambiente a thread singolo.

System.Web.UI.Timer, un componente ASP.NET che esegue postback asincroni o sincroni delle pagine Web a intervalli regolari.


1

Le due classi sono funzionalmente equivalenti, tranne quello System.Timers.Timer ha un'opzione per invocare tutti i callback di scadenza del timer tramite ISynchronizeInvoke impostando SynchronizingObject . In caso contrario, entrambi i timer richiamano i callback di scadenza sui thread del pool di thread.

Quando si trascina un oggetto System.Timers.Timernell'area di progettazione di Windows Form, Visual Studio imposta SynchronizingObject sull'oggetto modulo, facendo sì che tutti i callback di scadenza vengano chiamati sul thread dell'interfaccia utente.


1

Da MSDN: System.Threading.Timerè un timer semplice e leggero che utilizza metodi di callback ed è servito da thread del pool di thread. Non è raccomandato per l'uso con Windows Form, perché i suoi callback non si verificano sul thread dell'interfaccia utente. System.Windows.Forms.Timerè una scelta migliore per l'utilizzo con Windows Form. Per la funzionalità timer basata su server, potresti prendere in considerazione l'utilizzo System.Timers.Timer, che genera eventi e presenta funzionalità aggiuntive.

fonte

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.