2010-05-12 9 views
43

In meiner Anwendung muss ich periodische Herzschläge an eine "Bruder" -Anwendung senden.System.Timers.Timer/Threading.Timer vs Thread mit WhileLoop + Thread.Sleep für periodische Aufgaben

Ist dies besser mit System.Timers.Timer/Threading.Timer oder Verwenden eines Threads mit einer while-Schleife und einem Thread.Sleep?

Das Heartbeat-Intervall beträgt 1 Sekunde.

while(!exit) 
{ 
    //do work 
    Thread.Sleep(1000); 
} 

oder

myTimer.Start(() => { 
         //do work 
         }, 1000); //pseudo code (not actual syntax)... 

Antwort

32

System.Threading.Timer hat meine Stimme.

System.Timers.Timer ist für die Verwendung in serverbasierten (Timer-Funktion) Server-basierten (Ihr Code läuft als Server/Dienst auf einem Host-Computer statt von einem Benutzer ausgeführt wird).

Ein Thread mit einer While-Schleife und einem Thread.Sleep-Befehl ist wirklich eine schlechte Idee angesichts der Existenz robuster Timer-Mechanismen in .NET.

+2

und du hast meine. – Alan

+2

@Alan: und Sie haben meine – abatishchev

+3

Die System.Timers.Timer-Klasse kann wirklich in einem Benutzermodus Anwendung genauso einfach wie System.Threading.Timer verwendet werden. Intern verwendet System.Timers.Timer System.Threading.Timer für seinen internen Timing-Mechanismus und umschließt es nur, um Probleme mit der Entwurfszeit zu behandeln ... –

22

Server Timers sind eine andere Kreatur als schlafende Fäden.

Zum einen kann, abhängig von der Priorität Ihres Threads, und was sonst noch ausgeführt wird, Ihr schlafender Thread geweckt werden oder nicht und in dem von Ihnen angeforderten Intervall ausgeführt werden. Wenn das Intervall lang genug ist und die Genauigkeit der Planung keine Rolle spielt, ist Thread.Sleep() eine vernünftige Wahl.

Timer hingegen können ihre Ereignisse in einem beliebigen Thread auslösen, was bessere Planungsfunktionen ermöglicht. Die Kosten für die Verwendung von Timern sind jedoch ein wenig komplexer in Ihrem Code - und die Tatsache, dass Sie möglicherweise nicht in der Lage sind, zu steuern, welcher Thread die Logik ausführt, auf der das Timer-Ereignis ausgelöst wird. Aus der Dokumentation:

Die serverbasierte Timer ist für Verwendung mit Worker-Threads in einer Multithreaded-Umgebung entwickelt. Server Timer können zwischen Threads verschieben, um behandeln das erhöhte Elapsed-Ereignis, Ergebnis in mehr Genauigkeit als Windows-Timer bei der Erhöhung des Ereignisses auf Zeit.

Eine weitere Überlegung ist, dass Zeitgeber ihren Elapsed-Delegaten für einen ThreadPool-Thread aufrufen. Je nachdem, wie zeitaufwändig und/oder kompliziert Ihre Logik ist, möchten Sie sie möglicherweise nicht im Thread-Pool ausführen. Möglicherweise möchten Sie einen dedizierten Thread. Ein weiterer Faktor bei Zeitgebern ist, dass, wenn die Verarbeitung lange genug dauert, das Zeitgeberereignis erneut (gleichzeitig) auf einem anderen Thread ausgelöst werden kann - was ein Problem sein kann, wenn der gerade ausgeführte Code nicht für Gleichzeitigkeit vorgesehen oder strukturiert ist.

Sie Server Timer mit "Windows Timers" nicht verwirren. Letzteres bezieht sich in der Regel auf WM_TIMER-Nachrichten, die an ein Fenster gesendet werden können, sodass eine App die zeitgesteuerte Verarbeitung für ihren Hauptthread planen und darauf reagieren kann, ohne zu schlafen. Windows-Timer können sich jedoch auch auf die Win API for low-level timing beziehen (die nicht mit WM_TIMER identisch ist).

+0

Danke für die Antwort. Ich bin ein wenig verwirrt zwischen "Server Timers" und "Windows Timers" und wie das mit System.Threading.Timer und Thread.Sleep zusammenhängt. – Alan

+1

Okay, System.Timers.Timer ist ein Server-Timer. Erwischt! – Alan

+0

Im Allgemeinen ist es eine schlechte Idee, einen vollen Faden zu verschwenden, der meistens schläft. Threads sind schwergewichtig und es empfiehlt sich, eine der ThreadPool-basierten Alternativen zu verwenden. –

20

Weder :)

Schlafen ist in der Regel verpönt (leider kann ich die Einzelheiten nicht mehr erinnern, aber für einen, ist es ein Unterbrechungsfreie „Block“) und Timer s kommt mit vielen Gepäck. Wenn möglich, würde ich System.Threading.AutoResetEvent als solche

// initially set to a "non-signaled" state, ie will block 
// if inspected 
private readonly AutoResetEvent _isStopping = new AutoResetEvent (false); 

public void Process() 
{ 
    TimeSpan waitInterval = TimeSpan.FromMilliseconds (1000); 

    // will block for 'waitInterval', unless another thread, 
    // say a thread requesting termination, wakes you up. if 
    // no one signals you, WaitOne returns false, otherwise 
    // if someone signals WaitOne returns true 
    for (; !_isStopping.WaitOne (waitInterval);) 
    { 
     // do your thang! 
    } 
} 

Mit einem AutoResetEvent (oder seinem Vetter ManualResetEvent) garantiert einen echten Block mit Thread-sicher-Signalisierung (für solche Dinge wie graziös Kündigung oben) empfehlen. Im schlimmsten Fall ist es eine bessere Alternative zu Sleep

this helps :)

+0

Ich mag es, die Möglichkeit, Ihren Thread sauber herunterzufahren, ist nett. –

+6

Warum eine for-Schleife statt während? – gav

+2

@gav, 'while' funktioniert genauso gut,' for' ist eine stilistische Vorliebe. –

1

ich gefunden habe, dass die einzige Timer-Implementierung, die tatsächlich skaliert System.Threading.Timer ist. Alle anderen Implementierungen scheinen ziemlich falsch zu sein, wenn Sie mit einer nicht unbedeutenden Anzahl von geplanten Elementen zu tun haben.

Verwandte Themen