Laden...

[erledigt] Bestimmte Aktion *exakt* alle 20ms ausführen

Letzter Beitrag vor 15 Jahren 26 Posts 5.495 Views
[erledigt] Bestimmte Aktion *exakt* alle 20ms ausführen

Moin,

wir wollen bestimmte Berechnungen wiederholt ausführen, und zwar in exakten Zeitintervallen. Die Intervalle sollen exakt 20ms dauern. Nicht mehr, nicht weniger. Es geht hier um höchste Präzision. Dafür verwenden wir bisher einen System.Timers.Timer, dessen Intervall wir auf 20ms gesetzt haben. Das Problem dabei ist: Dieses Intervall wird nie exakt eingehalten. Eine Beispielausgabe ohne weitere Berechnungen, die alle 20ms die bisher vergangene Zeit (in ms) ausgeben soll, liefert folgendes Ergebnis:
...
1778
1809
1841
1872
1903
1934
...
Wie man sieht, stimmt das 20ms-Intervall hinten und vorne nicht. Der Prozessor selbst ist durchaus in der Lage, so schnell zu arbeiten, das haben wir schon getestet. Selbst, wenn wir gar keine Berechnungen vornehmen, stimmen die Intervalle nicht.

Ein Thread.Sleep() kommt für uns nicht in Frage, da dass den laufenden Thread anhalten würde. Das macht aber keinen Sinn, da wir die Zwischenzeiten "unbelastet" halten möchten. Entsprechend wollen wir natürlich auch etwas wie while(zeit<20ms) vermeiden, da der Prozessor nicht sinnlos ausgelastet werden soll.

Was können wir tun, um
1: das System.Timers.Timer.Interval exakt funktionieren zu lassen
oder
2: selbst eine Funktion zu implementieren, die nach einer exakten Zeitvorgabe den Anstoß zu einer neuen Berechnung gibt, ohne in der Zwischenzeit alles andere zu blockieren?

Grüße
zwei Anfänger 😃

in kurz: mit .net habt ihr bei sowas keine chance.

grund ist, das wenn der thread, der dafür verantworlich ist, gerade mehr zu tun hat, dann habt ihr schon ungereimtheiten aber der wohl wichtigste grund ist, das der garbagecollector zu jedem zeitpunkt den prozess anhalten kann um aufzuräumen und das macht exaktes timing immer zunichte.

Sowas haben wir uns fast gedacht. Gibt es die Möglichkeit selber etwas zu implementieren? Eine Art eigenen Timer basteln? Wobei einem da wahrscheinlich wieder mindestens der GC reinfunken würde...

Grüße

Wobei einem da wahrscheinlich wieder mindestens der GC reinfunken würde...

korrekt.

Kann doch die entprechenden Abschnitte als unsafe markieren.

Da funkt dann doch der GC nicht mehr rein, oder?

Ansonsten: Code in C (oder wahlweise ASM)

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

Es gibt unter Windows in keiner Sprache eine Möglichkeit exacte Timings hinzubekommen.

Es gibt nur sehr wenige Echtzeit systeme die das zulassen.

Hmm, ADA wurde als Echtzeitsprache entworfen und (tldr;) die Headline hier behauptet das würde mit Windows funktionieren:

http://www.electronicstalk.com/news/adf/adf124.html

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

Kann doch die entprechenden Abschnitte als unsafe markieren.

Da funkt dann doch der GC nicht mehr rein, oder?

unsafe bedeutet nicht unmanaged. unsafe heißt nur "not typesafe". der gc räumt auch im unsafekontext auf und außerdem hält er den gesamten prozess an um aufzuräumen und das betrifft auch pinvokeaufrufe mit allem was dahinter hängt.

Gut zu wissen. Bin jetzt erstmals auch auf das "fixed" Keyword gestoßen, welches dem GC mitteilt sich nicht einzumischen.

Wenn der dies allerdings auf Prozessebene macht, bringt das ja rein gar nichts wenn man die Delays umgehen will.

Shift to the left, shift to the right!
Pop up, push down, byte, byte, byte!

YARRRRRR!

Lad dir mal TwinCAT runter, das installiert dir einen Echtzeit-Kernel, der das Betriebssystem als eine Task laufen lässt. Dann kannst du C-Code implementieren, der als übergeordnete Task abgearbeitet wird oder lässt deine Berechnung direkt als SPS-Programm bearbeiten. Über eine ADS-dll kannst du dann ganz einfach Daten zwischen C# und SPS austauschen.

TwinCAT: http://www.beckhoff.de/german/twincat/tcatdow.htm
Doku: http://infosys.beckhoff.com/
Guck mal nach R3IO und ADS.

Signatur.Text = "Greetz, Neals";

Schaut ziemlcih kompliziert aus, evtl. kann man das was DeFlix erreichen will, anders implementieren. Leider verrät er nichts über das Ziel der Berechnung bzw. welche Daten verarbeitet werden, daher sind alle Vorschläge in die Richtung pure Spekulation.

Aber mal als Beispiel: Wenn man von einem A/D-Wandler Werte empfängt und die in einem exakten Zeitintervall auswerten muß, kann man die empfangenen Daten auch irgendwo zwischenspeichern und dann die Berechnung mit den zwischengespeicherten Werten durchführen. Auch dann ist natürlich nicht gegeben, daß der Wert zur Zeit X dort vorhanden ist, aber man kann diesen Wert ja aus dem vorhergehenden und dem nächsten Wert interpolieren.

Vielleicht ist diese Herangehensweise etwas näherliegend als die Installation eines Echtzeitkernels (was auch immer das ist) 🙂

Christian

Weeks of programming can save you hours of planning

Hallo zusammen,

da der Windows Scheduler (sozusagen) unberechenbar ist, können unter Windows direkt keine RealTime Anwendungungen entwickelt werden.

Anderer Ansatz wäre, wenn etwas zwar alle 20 ms ausgeführt werden soll, aber es nicht so schlimm wäre, wenn die Zeitscheiben mal früher oder später ausgeführt werden dürfen, wobei bei .NET unbedingt der Laufzeitzyklus gemessen werden muss, weil 20ms sehr sehr kurz ist 😉

Andere Lösungsansätze sind, wie schon im Vorfeld genannt: Alternativ Kernel verwenden, der ggf. zwischen Realtime Prozessen und Windows umschaltet, so dass der Kernel garantiert, dass Echtzeitanwendungen in time funktionieren.

Grüße
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

Vielleicht hilft das, unter Windows wird das, wie angesprochen, wohl nicht gehen...

QNX

Guten Morgen,

leider sind wir gezwungen, in .NET zu bleiben. Es hilft also alles nichts, wir müssen mit den Verzögerungen leben.

Ein paar Tests gestern haben ergeben, dass der Timer nur auf etwa 15,5ms genau arbeitet. Auch das noch recht unzuverlässig, aber bei mehreren hunderttausend Werten mittelt es sich darauf ein. Das heißt also, dass das Intervall (im Durchschnitt) immer ein Vielfaches von grob 15,5 ist. Im Test konnten wir folgendes feststellen: Gibt man ein Intervall von 2ms an, dauert es 15ms. Gibt man 10ms an, dauert es auch 15ms. 30ms werden zu 31ms, 50ms zu 62ms und 100ms zu 109ms.

Unsere Konsequenz: Wir richten uns darauf ein, dass das Intervall durchschnittlich 8ms zu lang dauert (weil es durchschnittlich irgendwas zwischen 0 und 15ms länger dauert als man eigentlich angibt) und ziehen den Wert in unseren Berechnungen ab. Räudig, aber funktional. So gleichen wir verlorene Zeit im Mittel wieder aus.

Noch eine Bemerkung: Diese 15,5ms scheinen recht weit verbreitet zu sein. Auch DateTime.Now ist nur bis auf diese Schrittweite genau. Für Millisekundengenaue Messungen empfehlen wir System.Diagnostics.Stopwatch.

Vielen Dank für eure schnell und zahlreiche Hilfe!

Grüße

Mich wuerde interessieren wie ihr jetzt den GC an der Nase herumfuehrt?

be the hammer, not the nail!

Gar nicht, der werkelt weiter fleißig rum. Der GC scheint nur für so wenig Verzögerungen zu sorgen, dass es beim Massentest nicht auffällt. Das eigentliche Problem scheint eigentlich nur die grobe Schrittweite des kleinsten Intervalls zu sein. Und die gleichen wir aus, indem wir einen durch Tests ermittelten Gegenwert mit einrechnen.

Hallo DeFlix,

Ein Thread.Sleep() kommt für uns nicht in Frage, da dass den laufenden Thread anhalten würde. Das macht aber keinen Sinn, da wir die Zwischenzeiten "unbelastet" halten möchten.

Was meinst du damit?

Thrad.Sleep macht nichts anderes als die Zeit die angebeben wurde, dem Scheduling von Windows zurückzugeben und bei Bedarf anderen Threads zur Verfügung zustellen.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Hallo DeFlix,

Ein paar Tests gestern haben ergeben, dass der Timer nur auf etwa 15,5ms genau arbeitet. Auch das noch recht unzuverlässig, aber bei mehreren hunderttausend Werten mittelt es sich darauf ein. Das heißt also, dass das Intervall (im Durchschnitt) immer ein Vielfaches von grob 15,5 ist. Im Test konnten wir folgendes feststellen: Gibt man ein Intervall von 2ms an, dauert es 15ms. Gibt man 10ms an, dauert es auch 15ms. 30ms werden zu 31ms, 50ms zu 62ms und 100ms zu 109ms.

Ich hoffe ihr habt das auch auf anderen Rechnern getestet, und auch mit einer Konstellation wo viele Prozesse gleichzeitig laufen, und ggf. auch ein Prozess mit höherer Priorität dabei ist etc...

Ich würde mich nicht blind auf die 15 ms verlassen.

Grüße
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

Jupp, wir haben das mehrfach getestet, auf unterschiedlichen Rechnern. Auch mit unterschiedlicher Auslastung der CPU, der Festplatte.... Der Fakt, dass das gleiche Problem auch bei DateTime.Now auftaucht, legt den Verdacht nahe, es handle sich um ein allgemeines Zeitmessproblem von Windows/.NET.

edit: Unterschiedliche Prios haben wir total vergessen. Das müssen wir unbedingt nochmal probieren. Danke für den Hinweis! Am Ende bekommen die einzelnen Prozesse alle nur verschiedene Zeiten, je nach Priorität - das würde uns schon ein bisschen erschrecken, wenn man sich Multirasiking so einfach macht 😉

Grüße

Welchen Timer zur Zeitmessung nutzt du eigtl.?
Das wäre normal eine Aufgabe für High-Performance Timer in C#

Interessant wäre auch ein Test mit Thread.Sleep und einer hohen oder niedrigen ThreadPriority

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

wie wäre es, wenn ihr die berechnungen in einen eigenen prozess auslagert und die priorität auf RealTime setzt?

was für timer habt ihr eigendlich getestet? es gibt da einige im framework und auch ein paar im netz die äußerst gut sind.

tipp: wenn ihr in dem berechungsthread seid, dann misst mal die anzahl der gc-collections mit einer version die viele klassen verwendet und eine version die eher nur structs verwendet. so könnt ihr die anzahl der collects auf ein mindestmaß reduzieren. wenn ihr klassen verwendet, versucht sie immer wiederzuverwenden. also nicht einfach mit new erstellen sondern einfach nur eine nicht mehr verwendete zu nehmen und mit neuen werten zu befüllen. z.b. ein singleton der alle instanzen cached und recycled.

  1. Stopwatch benutzt intern High performance counter,hat nur einen fallback,falls dieser nicht unterstützt wird.

  2. ein Multimediatimer wäre hier vllt. angebracht, da er nicht den 15,5 ms intervall hat.
    http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx

Timertest:http://www.codeproject.com/KB/cs/LP_TimerTest.aspx

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Vielen Dank für eure zahlreichen antworten.

Wie haben es jetzt mit unterschiedlichen Prio's getestet, aber immernoch das selbe Ergebnis, es läuft also soweit stabil und korrekt.
Das Sleep() kommt leider nicht in Frage, da wir nur einen Thread haben und wir noch andere Berechnungen durchführen wollen während wir warten.

Die anderen Sachen können leider nicht mehr getestet werden, da diese Woche keine Zeit mehr für dieses Projekt ist.

Vielen Dank und bist nächste Woche ;o)

huhu,

Interessant wäre auch ein Test mit Thread.Sleep und einer hohen oder niedrigen ThreadPriority

daran hate ich auch schon mal gedacht - naja, habs jetzt mal kurz ausprobiert. Timer mit Stopwatch, Thread.Sleep(), kein GC dabei.

Man erreicht mit Thread.Sleep() eine Genauigkeit die max. 1 ms über dem eingestelleten Wert liegt. Bei sehr niedrigen Werten (Sleep < 5) ist es ein wenig mehr. Die Priority ergab hier erstmal keinen Unterschied.

Noch als ergänzung: das ganze war natürlich nur ein rudimentärer Test mit einer einfachen Routine.

🙂

Xynratron

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

Echtzeit fähigkeit ist so eine Geschichte.
Oben habe ich von TwinCAD gelesen, Beckhoff, die dieses System vertreiben, wirbt mit Echtzeit fähigkeit, jedoch definieren sie echtzeit als >20ms, da dies für die üblichen Anwendungen mit deren System ausreicht.
Ich denke, dass echte echtzeitfähigkeit nur über einen Microcontroller mit hochgenauem Quarz umzusetzten ist, aber das kommt hier wohl leider nicht in frage.

Der Multimediatimer sieht sehr interessant aus. Den sehen wir uns morgen mal an.

Bis dahin