Was ist der Unterschied zwischen Thread.Sleep(timeout) und ManualResetEvent.Wait(timeout)?
-
24-10-2019 - |
Frage
Beide Gewinde.Sleep(timeout) und resetEvent.Wait(timeout) die Ausführung pause für mindestens timeout
Millisekunden, so gibt es einen Unterschied zwischen Ihnen?Ich weiß, dass Thread.Schlaf bewirkt, dass der thread zu geben, den Rest seiner Zeitscheibe, so womöglich einen erholsamen Schlaf, dauert viel länger als gefragt.Hat die Wartezeit(timeout) - Methode eines ManualResetEvent-Objekt das gleiche problem haben?
Bearbeiten:Ich bin mir bewusst, dass ein ManualResetEvent, die Hauptsache ist, signalisiert werden, aus einem anderen thread - jetzt bin ich nur noch beschäftigt mit dem Fall eines Ereignisses Warten Methode mit einem timeout angegeben ist, und die keine anderen Anrufer Einstellung der Veranstaltung.Ich möchte wissen, ob es mehr zuverlässig zu Erwachen, auf-Zeit als Thread.Schlafen
Lösung
Thread.Sleep(timeout)
verursacht eine bedingungslose Wartezeit, bevor die Ausführung wieder aufgenommen wird. resetEvent.WaitOne(timeout)
Bewirkt, dass der Faden wartet, bis entweder (1) das Ereignis ausgelöst wird, oder (2) das Timeout erreicht ist.
Es geht darum, Ereignisse zu verwenden, um sie von einem anderen Thread auszulösen, sodass Sie direkt steuern können, wenn der Faden aufwacht. Wenn Sie dies nicht benötigen, sollten Sie keine Ereignisobjekte verwenden.
Bearbeiten: Timing In Bezug auf sind beide gleichermaßen zuverlässig. Ihr Kommentar zum "pünktlichen Erwachen" macht mich jedoch Sorgen. Warum brauchen Sie Ihren Code, um pünktlich aufzuwachen? Sleep
und WaitOne
Sie sind nicht wirklich mit Präzision konzipiert.
Nur wenn timeout
ist unter 50 ms oder so und Sie benötigen die Zuverlässigkeit, Sie sollten sich mit alternativen Timing -Methoden befassen. Dieser Artikel Sieht nach einem ziemlich guten Überblick aus.
Andere Tipps
Der Hauptunterschied zwischen Thread.Sleep
und ManualResetEvent.WaitOne
ist, dass Sie einem Faden signalisieren können, der auf einen Handbuch wartet Satz Methode, wodurch der Thread früher als die Zeitüberschreitung aufwacht.
Wenn Sie nicht signalisieren, würde ich erwarten, dass sie sich auf sehr ähnliche Weise verhalten.
Aus .NET -Reflektor kann ich sehen, dass die Methode ManualResetEvent.WaitOne
führt schließlich zu einem Aufruf einer externen Methode mit der folgenden Signatur:
int WaitOneNative(SafeWaitHandle waitHandle,
uint millisecondsTimeout,
bool hasThreadAffinity,
bool exitContext);
Wohingegen Thread.Sleep
Ruft diese externe Methode auf:
void SleepInternal(int millisecondsTimeout);
Leider habe ich nicht den Quellcode für diese Methoden, also kann ich nur raten. Ich würde mir vorstellen, dass in beiden Anrufen der Thread geplant wird, während er darauf wartet, dass die Zeit abgelaufen ist, wobei keiner besonders genauer als der andere ist.
Für Verzögerungen und Perioden habe ich Monitor gefunden. Warte eine gute Wahl.
object timelock = new object();
lock (timelock) { Monitor.Wait(timelock, TimeSpan.FromMilliseconds(X.XX)); }
Dies ergibt ein hervorragendes Ergebnis ... ~ 1 ms Jitter oder besser, abhängig von Anwendungsspezifikationen.
Wie Sie vielleicht bereits wissen, ist Thread.sleep (x) unzuverlässig und kann nicht abgesagt werden ... Ich vermeide es wie die Pest.
Die Sleep () - Funktion nicht auf diese Weise gearbeitet haben für eine lange Zeit.Die Genauigkeit ist bestimmt durch die multimedia-timer Zeit, etwas, was Sie ändern können, indem Sie P/Aufrufen timeBeginPeriod().Leider, auf meinem Rechner habe ich eine Art von Programm, die diese Zeit zu einer Millisekunde, wodurch schläft genaue herab zu einer Millisekunde.Hier finden Sie den code, um zu versuchen, für sich selbst:
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
//timeBeginPeriod(1);
var sw1 = Stopwatch.StartNew();
for (int ix = 0; ix < 100; ++ix) Thread.Sleep(10);
sw1.Stop();
var sw2 = Stopwatch.StartNew();
var mre = new ManualResetEvent(false);
for (int ix = 0; ix < 100; ++ix) mre.WaitOne(10);
sw1.Stop();
Console.WriteLine("Sleep: {0}, Wait: {1}", sw1.ElapsedMilliseconds, sw2.ElapsedMilliseconds);
Console.ReadLine();
//timeEndPeriod(1);
}
[DllImport("winmm.dll")]
private static extern int timeBeginPeriod(int period);
[DllImport("winmm.dll")]
private static extern int timeEndPeriod(int period);
}
Die Ausgabe auf meiner Maschine:
Schlafen:999, Warten:1003
mit einer Variabilität von etwa 5 Millisekunden.
Wie andere erwähnt haben, könnte der Unterschied darin bestehen, dass Waitone vor der Schlafzeit zurückkehren könnte, wenn sie signalisiert werden. Der Schlaf wartet garantiert auf die Schlafzeit.
Thread.Seep in Reflektoraufrufen:
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void SleepInternal(int millisecondsTimeout);
ManualResetEvent.wait bei Reflektoranrufen:
private static extern int WaitOneNative(SafeWaitHandle waitHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);
Ich bin mir nicht sicher, ob es einen Unterschied zwischen den beiden gibt, aber ich werde sehen, ob ich etwas finden kann.
Der Schlaf setzt sich für die angegebene Zeit fort. Das Ereigniswart kann früher enden, wenn das Ereignis signalisiert wird. Dies ist der Zweck von Ereignissen: Er lassen einen Thread einen anderen aufwachen.
In einem Thread würden Sie sagen:
mre.WaitOne(10000); // ten seconds
Console.WriteLine("Woke up!");
In einem anderen würden Sie sagen:
mre.Set(); // this causes `WaitOne` to return in the first thread
Ohne den Anruf zu Set
Im anderen Faden würde der erste Faden 10 Sekunden lang effektiv schlafen.