Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Ungenauigkeit von TDateTime / Alternative? (https://www.delphipraxis.net/131628-ungenauigkeit-von-tdatetime-alternative.html)

Antigo 27. Mär 2009 22:31


Ungenauigkeit von TDateTime / Alternative?
 
Hi,
Ich möchte gerne JEDE Sekunde eine Aktion ausführen und diese dann samt Ergebnis zu späteren Analyse Zwecken abspeichern. Dabei ist es mir wichtig, das ich auch wirklich für jede Sekunde ein Ergebnis erhalte.

Deshalb hab ich meinen Timer, der sekündlich diese Aktion anstoßen soll, auch nicht einfach mit 1000ms getacktet, sondern mit 1ms. Und in jedem Durchlauf frage ich dann ab, ob seit der letzten Aktion schon eine Sekunde vergangen ist.

Das heisst, wenn ich die Aktion ausfühe speichere ich unter FlastAction vom Typ TDatime das aktuelle Datum/Uhrzeit folgendermaßen:

Delphi-Quellcode:
Flastaction: TDateTime;
//...
FLastAction:=Now;
Dann frage ich in jedem Timer Aufruf

Delphi-Quellcode:
if SecondsBetween(Now,FLastAction) > 0 then
  //Stoße nächste Aktion an, speicher Now als FlastAction und als Startpunkt der Aktion
Nun passierte es häufiger, dass ich dann beim Auswerten der Datensätze nur 59 Aktionen in der Minute hatte, d.h. iwie wurde einmal nichts ausgelöst. Und etwas rechenintensives, dass auch nur annäherend für 1 sec das Hauptprogramm blockieren würde ist nicht dabei.

Jetzt hab ich testweise etwas ganz blödes gemacht und statt secondsbetween folgendes benutzt:
Delphi-Quellcode:
if FormatDateTime('ss',Now)<>FormatDateTime('ss',FLastAction) then
    //Stoße nächste Aktion an, speicher Now als FlastAction und als Startpunkt der Aktion
und jetzt habe ich plötzlich durchgehend meine 60 Aktionen pro Minute.

Jetzt meine Fragen:
- Ist das Zufall und wenn ich Pech hab verlier ich hin und wieder trotzdem mal ein paar Sekunden?
- Gibt es vielleicht eine andere Möglichkeit jede Sekunde etwas auszuführen?
Da es eigentlich nicht an zuviel
Rechenaufwand für eine Sekunde liegen kann, würde mich da auch ein extra Thread nicht wirklich weiterbringen oder?

:gruebel:

Die Muhkuh 27. Mär 2009 22:36

Re: Ungenauigkeit von TDateTime / Alternative?
 
Mit nem Timer bekommste sowieso keine 1ms hin, da brauchste schon einen Multimediatimer.

jfheins 27. Mär 2009 22:42

Re: Ungenauigkeit von TDateTime / Alternative?
 
1/60 einer Sekunde ist ungefähr 17 Millisekunden.

Genauer als 17 Millisekunden geht dein Timer sowiso nicht. Da du in deinem ersten Versuch guckst, ob mehr als eine Sekunde vergangen ist, kann es duchaus passieren, dass mal nicht eine Sekunde, sondern 10-25 Millisekunden vergangen sind.

Wenn jetzt zwischen jeder Aktion 1 Sekunde und 17 Millisekunden vergehen hast du nach 59 Aktionen ... tadaaa 60 Sekunden benötigt.

Der zweite Versuch funktioniert, da er nicht immer auf die letzte Aktion zurückblickt (die ja einen Hauch verspätet eingetreten ist) sondern an den Anfang.

xZise 27. Mär 2009 22:45

Re: Ungenauigkeit von TDateTime / Alternative?
 
Hallo Michael,
Also die kleinste Abtastrate (mit Standardkomponenten) ist 16 ms (ungefähr), aber das ist eher nebensächlich. Ich wollte halt nur gesagt haben, das der Timer nicht zwingend jede Millisekunde ausgeführt wird.

Zudem würde ich, wenn es nicht hundertprozentig eine Sekunde sein sollen (also 1,015 Sekunden würden auch gehen), würde ich statt ein TDateTime einfach GetTickCount also Cardinal nehmen.

Delphi-Quellcode:
var
  LastTick : Cardinal;

procedure ...Timer(...
begin
  if GetTickCount - LastTick >= 1000 then
  begin
    ...
    LastTick := GetTickCount;
  end;
end;
Oder alternativ einfach das Intervall auf einer Sekunde belassen? Oder was spricht dagegen?

MfG
xZise

Antigo 27. Mär 2009 22:56

Re: Ungenauigkeit von TDateTime / Alternative?
 
erstmal danke für die schnellen Antworten.

Zum Timer Intervall: ja mir ist klar das der Timer nicht wirklich jede Millisekunde aufgerufen wird. Ich wollte auch nur das kleinstmöglichste Intervall erreichen und das hab ich so ja ^^


Wegen dem Intervall von einer Sekunde: Ich hatte halt überlegt das die Timer sicher nicht so wahnsinnig genau ist. Und wenn er jedesmal erst nach 1,1 Sekunden auslöst hab ich ja nach 10 Sekunden eine Sekunde verloren. Deshalb die Lösung mit dem kleineren Intervall, so dass ich eben früher merke wann die nächste Sekunde anfängt.


Zitat:

Zitat von jfheins
1/60 einer Sekunde ist ungefähr 17 Millisekunden.

Genauer als 17 Millisekunden geht dein Timer sowiso nicht. Da du in deinem ersten Versuch guckst, ob mehr als eine Sekunde vergangen ist, kann es duchaus passieren, dass mal nicht eine Sekunde, sondern 10-25 Millisekunden vergangen sind.

Wenn jetzt zwischen jeder Aktion 1 Sekunde und 17 Millisekunden vergehen hast du nach 59 Aktionen ... tadaaa 60 Sekunden benötigt.

Der zweite Versuch funktioniert, da er nicht immer auf die letzte Aktion zurückblickt (die ja einen Hauch verspätet eingetreten ist) sondern an den Anfang.

Werden bei TdateTime denn auch die millisekunden mitgespeichert? Wenn ja dann stimmt das natürlich weil ich ja dann darauf warte, dass seit der letzten Aktion mind 1 Sekunde vergangen ist. Ich will ja aber darauf warten, dass der Sekundenzeiger umspringt, also FormatDateTime('ss',Now) eine andere Zeit ausspuckt, als bei der letzten Aktion und da hilft mir ein GettickCount auch nicht weiter.

Meine Fummel-Lösung mit dem Vergleich zweir FormatDateTime Ausdrücke hat jetzt jedenfalls 20 min lang perfekt funktioniert. Auch wenns mir irgendwie sehr gefrickelt vorkommt.

omata 27. Mär 2009 22:57

Re: Ungenauigkeit von TDateTime / Alternative?
 
Dabei sollte man vielleicht auch wissen, dass GetTickCount alle 55ms hochgezählt wird. Das sind dann 18.2mal pro Sekunde. Kleiner als 55ms wird es nicht gehen, das hat Billy damals unter DOS so definiert.

Luckie 27. Mär 2009 23:05

Re: Ungenauigkeit von TDateTime / Alternative?
 
Wenn es wirklich darauf ankommt zeitgenau etwas auszuführen, dann ist Windows die flasche Platform. Windows ist kein real-time Betriebssystem. Windows basiert auf Nachrichten. Das heißt, nicht man selber bestimmt, ob ein Ereignis eintritt, sondern der Gegenüber und man reagiert dann auf das Ereignis. Wobei hier Ereignis nicht unbedingt im OOP Sinne zu betrachten ist.

Das heißt, für deine Aufgabe hast du das falsche Betriebssyste. Warum muss denn unbedingt genau jede Sekunde etwas ausgeführt werden? Und was passiert, wenn das nicht der Fall ist? Eine saubere Lösung wäre von der Zeitabhängigkeit weg zu kommen und ereignisorientiert zu arbeiten.

jfheins 27. Mär 2009 23:15

Re: Ungenauigkeit von TDateTime / Alternative?
 
Zitat:

Zitat von Antigo
Werden bei TdateTime denn auch die millisekunden mitgespeichert? Wenn ja dann stimmt das natürlich weil ich ja dann darauf warte, dass seit der letzten Aktion mind 1 Sekunde vergangen ist. Ich will ja aber darauf warten, dass der Sekundenzeiger umspringt, also FormatDateTime('ss',Now) eine andere Zeit ausspuckt, als bei der letzten Aktion und da hilft mir ein GettickCount auch nicht weiter.

WSenn mich nicht alles täuscht ist TDateTime ein Double. Der kommt noch gut in den Millisekundenbereich hinein (von der Genauigkeit) der hier bei etwa 2*10^-7 liegt.

Wenn du wirklich darauf warten möchtest, dass der Sekundenzeiger umspringt, musst du wohl immer die aktuelle Sekunde ausrechnen lassen.

Antigo 27. Mär 2009 23:18

Re: Ungenauigkeit von TDateTime / Alternative?
 
Zitat:

Zitat von Luckie
Wenn es wirklich darauf ankommt zeitgenau etwas auszuführen, dann ist Windows die flasche Platform. Windows ist kein real-time Betriebssystem. Windows basiert auf Nachrichten. Das heißt, nicht man selber bestimmt, ob ein Ereignis eintritt, sondern der Gegenüber und man reagiert dann auf das Ereignis. Wobei hier Ereignis nicht unbedingt im OOP Sinne zu betrachten ist.

Das heißt, für deine Aufgabe hast du das falsche Betriebssyste. Warum muss denn unbedingt genau jede Sekunde etwas ausgeführt werden? Und was passiert, wenn das nicht der Fall ist? Eine saubere Lösung wäre von der Zeitabhängigkeit weg zu kommen und ereignisorientiert zu arbeiten.

joar ist mir alles klar aber ich möchte auch kein auf ms genaues Programm haben. Und auf eine Sekunde genau sollte möglich sein. Klappt ja auch mit der Gerfrickelten Lösung ganz gut.

Warum jede Sekunde? Nun ich hab zurzeit eine miese Internetverbindung und infolgedessen mal mehr und mal weniger Paket Loss. Mit meinem Programm möchte ich also um das ganze etwas zu überwachen, zu protokollieren und im Nachhinein zu Analysieren halt beständig eine Internetseite anpingen und mir die Antwortzeit merken bzw. ob es ein Timeout = Paketverlust gab.
Der sekündliche ping unter cmd.exe reicht da als Indikator schon aus. Wenn ich in einem Onlinespiel beispielsweise viele Lags (infolge von Paket Loss, wenn der Ping durchkommt ist die Antwort Zeit ok) hab, dann hab ich auch beim ping oft Zeitüberschreitungen.
Und um halt mal festzuhalten zu welchen Tageszeiten ich durchschnittlich wieviel Paketverlust hatte brauche ich halt beständige Daten. Da nützt es mir nix wenn ich einfach so oft pinge wies geht und wenn dann ein Paket verloren geht einfach 2 sek warte bis ich es als timeout zähle und dann weiterpinge. Das gäbe eine reichlich sinnfreie Statistik.
Ob meine Statistik jetzt sinnvoller ist sei mal dahingestellt ^^ Ist für meine Frage auch egal




Zitat:

Zitat von jfheins
Zitat:

Zitat von Antigo
Werden bei TdateTime denn auch die millisekunden mitgespeichert? Wenn ja dann stimmt das natürlich weil ich ja dann darauf warte, dass seit der letzten Aktion mind 1 Sekunde vergangen ist. Ich will ja aber darauf warten, dass der Sekundenzeiger umspringt, also FormatDateTime('ss',Now) eine andere Zeit ausspuckt, als bei der letzten Aktion und da hilft mir ein GettickCount auch nicht weiter.

WSenn mich nicht alles täuscht ist TDateTime ein Double. Der kommt noch gut in den Millisekundenbereich hinein (von der Genauigkeit) der hier bei etwa 2*10^-7 liegt.

Wenn du wirklich darauf warten möchtest, dass der Sekundenzeiger umspringt, musst du wohl immer die aktuelle Sekunde ausrechnen lassen.

Das muss ich dann wohl :s


danke an alle für die hilfe:)


edit: Ich werds dann aber wohl folgendermaßen lösen:
Delphi-Quellcode:
 
  if SecondOf(Now)>SecondOf(myPingModul.LastePing) then
  begin
sieht nicht mehr ganz so gruselig aus und müsste auch funktionieren

alzaimar 28. Mär 2009 09:07

Re: Ungenauigkeit von TDateTime / Alternative?
 
Ich würde im Timer-Ereignis einfach das Interval in Abhängigkeit von der Ungenauigkeit korrigieren. Hier ein Schnippel;

Delphi-Quellcode:
Procedure TForm1.StartButtonClick (Sender : TObject);
Begin
  Timer1.Interval := 1000;
  Start := Now;
  NumberOfSeconds := 0;
  Timer1.Enabled := True;
End;

procedure TForm16.Timer1Timer(Sender: TObject);
Var
  elapsed : Double;

begin
  elapsed := 86400*(Now-Start);
  inc (NumberOfSeconds );
  Timer1.interval := Trunc(1000*(1 - Elapsed + NumberOfSeconds )); // Interval korrigieren
// Test-Code zum Anzeigen: Anzahl der Sekunden, vergangene Sekunden seit Start, korrigiertes Interval
  Memo1.Lines.add(Format('%.4d %8.1f %4d',[NumberOfSeconds , elapsed, timer1.interval]));
end;
Läuft wie ein Uhrwerk :mrgreen:


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:05 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz