Laden...

Wieso dauert ein Task.Delay(50) manchmal 900ms?

Erstellt von Mallett vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.131 Views
M
Mallett Themenstarter:in
171 Beiträge seit 2012
vor 4 Jahren
Wieso dauert ein Task.Delay(50) manchmal 900ms?

Hallo zusammen,

ich beiße mir gerade die Zähne aus an einem kleinen Problem. Es geht um einen Handshake mit einer SPS, eine Art Heartbeat sozusagen.

Dazu habe ich einen Task der in einer Schleife while(_heartbeatActive) läuft und regelmäßig das entsprechende Bit von der SPS liest. Regelmäßig heißt dabei so viel wie am Ende steht ein await Task.Delay(50) um nicht die CPU komplett auszulasten. Wenn der Wert true ist schicke ich asynchron eine Notification ab. Der Empfänger wartet dann 500ms und setzt den Wert wieder auf false, die SPS schreibt dann nach 500ms Wartezeit den Wert wieder auf true zurück usw.

Jetzt ist es so, dass das Ganze teilweise stundenlang funktioniert und plötzlich "verliere" ich eine Wertänderung, wodurch ich dann keine Notification mehr erzeuge, niemand mehr den Wert umtoggled und das Ganze dann stehen bleibt.

Nachdem ich jetzt ewig versucht habe, das Problem zu finden, hab ich es durch Logging (kann nicht debuggen auf dem Zielsystem) soweit eingrenzen können, dass im Fehlerfall die Zeile await Task.Delay(50) plötzlich 900ms oder länger braucht.

Über irgendeine Idee, wie das sein kann, würde ich mich freuen.

16.833 Beiträge seit 2008
vor 4 Jahren

"Warten" kann niemals genau sein, was daran liegt wie eben "Warten" technisch funktioniert.
50 wirste eh nie erreichen; Der Faktor von 50 auf 900ms ist aber sehr hoch, ungewöhnlich hoch. Technisch prinzipiell möglich aber der Faktor ist zu hoch als das ohne Grund der Fall wäre.

Es muss also noch irgendwas anderes rein spielen.
Ich vermute, dass es evtl. an der gesamten Implementierung liegt. Code?

6.911 Beiträge seit 2009
vor 4 Jahren

Hallo Mallett,

Ich vermute, dass es evtl. an der gesamten Implementierung liegt. Code?

Das vermute ich auch. Wenn "ungünstig" implementiert, so bauen sich eine Menge WaitHandles, etc. auf die der GC dann mühevoll abräumen muss.
Ohne ganz ins Details zu gehen: .NET hat eine "Timer-Queue" die idealerweise kurz ist, aber wenn eine Menge Timer erstellt werden, so kann diese Queue sehr groß werden. Neben der Arbeit für den GC ist auch für den Scheduler mühsam alle Timer der Queue abzuarbeiten.
Daher ist korrektes verwenden eines Timers wichtig, damit es effizient arbeiten kann.

Kannst du im Live-System den Speicherverbrauch und / oder GC-Stats der App beobachten?
Bei .NET Core via dotnet-counters, bei .NET Full über die Windows-Leistungsindikatoren.

Aber ohne Code, nur anhand deiner Beschreibung, lässt sich nur raten...

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"