Thread.Sleep (1) dauert länger als 1 ms [duplizieren]

8

Ich habe diese Frage durchsucht, aber keine Antwort gefunden. Wenn es ein Duplikat ist, schließe ich es gerne.

Ich versuche derzeit eine Leistungsbewertung für eine Technologie zu machen und habe einige ziemlich unglaubliche Ergebnisse gesehen, also habe ich beschlossen, etwas zu experimentieren. Darin wollte ich versuchen zu sehen, ob die Stoppuhr-Klasse zurücklief, was ich erwartet hatte.

%Vor%

In diesem Fall habe ich einen Rückgabewert von 15ms gesehen. Ich verstehe die Auflösung von DateTime um dort zu sein aber sollte nicht Thread.Sleep (1) einen Thread für 1ms schlafen lassen? Das System, das ich bin, gibt Stoppuhr.IsHighResolution True zurück, und es wird in .NET 4 ausgeführt.

Hintergrund: Dieser Code in seiner vollständigen und korrekten Form soll einige Zahlen zu Aerospike db get Anfragen sammeln. Die DB ist nicht auf der gleichen Box. Als ich die sw.ElapsedMilliseconds ausgab, als eine Abfrage in der Mitte war, sehe ich meistens Antworten von unter einer Millisekunde, und das klingt etwas verdächtig, wenn man bedenkt, dass mein Java-gleichwertiger Code die meiste Zeit mehr glaubhafte Antworten von 5ms-15ms liefert. Der Java-Code verwendet den Unterschied von System.nanoTime (). Durch submilli Antworten in meinem C # Code meine ich Console.WriteLine (sw.ElapsedMilliseconds) druckt 0.

    
Rig 28.09.2013, 12:21
quelle

6 Antworten

27

Timer andere als Stoppuhr werden um den Takt-Interrupt erhöht. Was standardmäßig unter Windows 64 mal pro Sekunde tickt. Oder 15.625 Millisekunden. Wenn also ein Thread.Sleep () Argument kleiner als 16 nicht die Verzögerung liefert, nach der Sie suchen, erhalten Sie immer mindestens das 15.625-Intervall. Wenn Sie beispielsweise "Environment.TickCount" oder "DateTime.Now" lesen und less als 16 Millisekunden warten, lesen Sie den gleichen Wert zurück und denken, dass 0 ms vergangen sind.

Verwenden Sie die Stoppuhr immer für kleine Inkrementmessungen, sie verwendet eine andere Frequenzquelle. Die Auflösung ist variabel und hängt vom Chipsatz auf dem Motherboard ab. Aber Sie können sich darauf verlassen, dass es besser ist als eine Mikrosekunde. Stoppuhr.Frequenz gibt Ihnen die Rate.

Die Taktunterbrechungsrate kann geändert werden, Sie müssen timeBeginPeriod () anpinnen. Das kann Sie auf eine einzige Millisekunde bringen und Thread.Sleep (1) korrekt machen. Am besten, dies nicht zu tun, es ist sehr Macht unfreundlich.

    
Hans Passant 28.09.2013, 12:33
quelle
5

Ich erwarte, dass Thread.Sleep nichts weiter ist als ein managed Wrapper um das Win32 Sleep API. Es ist bekannt, dass diese API-Funktion eine niedrige Auflösung hat. Die Dokumentation sagt das:

  

Diese Funktion bewirkt, dass ein Thread den Rest seiner Zeitscheibe abgibt und für ein Intervall basierend auf dem Wert von dwMilliseconds nicht mehr ausführbar ist. Die Systemuhr "tickt" mit konstanter Rate. Wenn dwMilliseconds kleiner als die Auflösung der Systemuhr ist, kann der Thread für weniger als die angegebene Zeitdauer schlafen. Wenn dwMilliseconds größer als ein Tick, aber kleiner als zwei ist, kann die Wartezeit zwischen einem und zwei Ticks liegen und so weiter. Um die Genauigkeit des Schlafintervalls zu erhöhen, rufen Sie die timeGetDevCaps-Funktion auf, um die unterstützte minimale Timerauflösung zu ermitteln, und die timeBeginPeriod-Funktion, um die Timerauflösung auf das Minimum zu setzen. Seien Sie vorsichtig beim Aufruf von timeBeginPeriod, da häufige Anrufe die Systemuhr, den Stromverbrauch des Systems und den Scheduler erheblich beeinflussen können. Wenn Sie timeBeginPeriod aufrufen, rufen Sie es früh in der Anwendung auf und stellen Sie sicher, dass Sie die Funktion timeEndPeriod am Ende der Anwendung aufrufen.

     

Nachdem das Schlafintervall abgelaufen ist, kann der Thread ausgeführt werden. Wenn Sie 0 Millisekunden angeben, gibt der Thread den Rest seiner Zeitscheibe ab, bleibt jedoch bereit. Beachten Sie, dass ein fertiger Thread nicht garantiert sofort ausgeführt werden kann. Folglich wird der Thread möglicherweise erst einige Zeit nach Ablauf des Schlafintervalls ausgeführt. Weitere Informationen finden Sie unter Planen von Prioritäten.

Sie könnten also timeBeginPeriod und timeEndPeriod wie vorgeschlagen verwenden, um die Timer-Auflösung zu erhöhen, aber das ist wirklich nicht zu empfehlen. Wenn Sie wirklich für kurze Zeit blockieren müssen, schlage ich vor, dass Sie eine bessere Lösung finden. Zum Beispiel ein Multimedia-Timer.

    
David Heffernan 28.09.2013 12:31
quelle
1

Ja, was Sie herausgefunden haben, ist absolut richtig.

Thread.Sleep garantiert nicht die Freigabe bei N Millisekunden. Es stellt sicher, dass Sleep nicht vor N Millisekunden freigegeben wird.

Mit anderen Worten: Thread.Sleep(1) bedeutet, dass Sleep mindestens eine Millisekunde dauert. Das Betriebssystem plant die Zeitscheibe für bestimmte Threads nicht für bestimmte Zeit.

  

Der Thread wird vom Betriebssystem für die angegebene Zeit nicht zur Ausführung geplant. Diese Methode ändert den Status des Threads, um WaitSleepJoin einzuschließen.

Von Msdn

    
Sriram Sakthivel 28.09.2013 12:29
quelle
1

Die Suche nach "thread sleep resolution" führt zu diesen verwandten SO-Fragen:

Einigkeit besteht darin, dass Sleep () standardmäßig mindestens 15 ms benötigt, es sei denn, Sie setzen die Auflösung mit timeBegin / EndPeriod () wie in diesem antworten .

    
devio 28.09.2013 12:33
quelle
0

Thread.Sleep (n) bedeutet, dass der aktuelle Thread für mindestens die Anzahl der Timeslices (oder Threadquanten) blockiert wird, die innerhalb von n Millisekunden auftreten können. Die Länge einer Zeitscheibe ist bei verschiedenen Versionen / Typen von Windows und verschiedenen Prozessoren unterschiedlich und liegt im Allgemeinen zwischen 15 und 30 Millisekunden. Dies bedeutet, dass der Thread fast immer für mehr als n Millisekunden blockiert. Die Wahrscheinlichkeit, dass Ihr Thread genau nach n Millisekunden wieder aufwacht, ist ungefähr so ​​unmöglich wie unmöglich. Also, Thread.Sleep ist sinnlos für das Timing.

    
OBV 28.09.2013 12:29
quelle
0

Thread.Sleep(1) wird einen Thread für 1ms in den Ruhezustand versetzen, aber Sie können diese Genauigkeit normalerweise nicht erreichen.

Sobald der Thread jedoch in den Schlafzustand übergeht, dauert es einige Zeit, bis der Kernel ihn in die Bereitschaftswarteschlange zurücksetzt und ihn dann in den Ausführungsstatus versetzt, wenn der Thread tatsächlich erneut ausgeführt wird.

All diese Faktoren hängen von der Plattform, der Anzahl der CPUs, der Anzahl der anderen Prozesse usw. ab. Bei Nicht-RT-Betriebssystemen können Sie dafür keine Garantie übernehmen.

    
Nemanja Boric 28.09.2013 12:29
quelle

Tags und Links