C#, Warum sind timer-Frequenzen extrem aus?
Beide System.Timers.Timer
und System.Threading.Timer
Feuer in Intervallen, sind erheblich Verschieden von der gewünschten diejenigen.
Zum Beispiel:
new System.Timers.Timer(1000d / 20);
ergibt sich ein timer löst 16-mal pro Sekunde, nicht 20.
Sicher sein, dass es gibt keine Nebenwirkungen von zu langen Ereignis-Handlern, schrieb ich dieses kleine test-Programm:
int[] frequencies = { 5, 10, 15, 20, 30, 50, 75, 100, 200, 500 };
//Test System.Timers.Timer
foreach (int frequency in frequencies)
{
int count = 0;
//Initialize timer
System.Timers.Timer timer = new System.Timers.Timer(1000d / frequency);
timer.Elapsed += delegate { Interlocked.Increment(ref count); };
//Count for 10 seconds
DateTime start = DateTime.Now;
timer.Enabled = true;
while (DateTime.Now < start + TimeSpan.FromSeconds(10))
Thread.Sleep(10);
timer.Enabled = false;
//Calculate actual frequency
Console.WriteLine(
"Requested frequency: {0}\nActual frequency: {1}\n",
frequency, count / 10d);
}
Die Ausgabe sieht wie folgt aus:
Angefordert: 5 Hz; aktuell: 4,8 Hz
Angefordert: 10 Hz; aktuell: 9,1 Hz
Angefordert: 15 Hz; aktuell: 12,7 Hz
Angefordert: 20 Hz; aktuell: 16 Hz
Angefordert: 30 Hz; aktuell: 21,3 Hz
Angefordert: 50 Hz; aktuell: 31,8 Hz
Beantragt: 75 Hz; aktuell: 63,9 Hz
Angefordert: 100 Hz; aktuell: 63,8 Hz
Angefordert: 200 Hz; aktuell: 63,9 Hz
Angefordert: 500 Hz; aktuell: 63,9 Hz
Der tatsächlichen Frequenz abweicht von bis zu 36% aus der angeforderte. (Und offenbar darf nicht mehr als 64 Hz.) Da Microsoft empfiehlt diese timer für die "höhere Genauigkeit" über System.Windows.Forms.Timer
, das verwirrt mich.
Btw, diese sind nicht zufällige Abweichungen. Es sind die gleichen Werte jedes mal.
Und ein ähnliches test-Programm für die anderen timer-Klasse System.Threading.Timer
, zeigt die exakt gleichen Ergebnisse.
In meinem eigentlichen Programm, ich brauche zu sammeln, die Messungen bei exakt 50 samples pro Sekunde. Sollte dies dennoch nicht benötigen eine real-time-system. Und es ist sehr frustrierend 32 samples pro Sekunde statt 50.
Irgendwelche Ideen?
@Chris:
Du hast Recht, die Intervalle scheinen alle ganzzahligen vielfachen von irgendwas um die 1/64th Sekunde. Btw, hinzufügen einen Thread.Sleep(...) in den event-handler nicht einen Unterschied machen. Das macht Sinn, gegeben, dass System.Threading.Timer
den threadpool verwendet, so dass jedes Ereignis ausgelöst wird, auf einen freien thread.
- Ich bin mir nicht sicher, dass: "Das darf doch nicht benötigen eine real-time-system." wahr sein kann, gegeben : "ich muss erfassen, Messungen bei genau 50 samples pro Sekunde."
- Der MultiMediaTimer (winmm.dll) Nutzung vorgestellt von Justin Tanner funktioniert perfekt. Vielen Dank, Mann.
- Ich bin damit einverstanden. Klingt wie eine harte Echtzeit-Anforderung zu mir - genau das, was ein RTOS gemeint ist, zu lösen. Veranstaltung alle 20ms mit einem guaranteeed Antwort von 1-2 ms.
- Wenn Sie müssen "genau 50 samples pro Sekunde" Ihre beste Wette ist, um eine externe platine, mikrocontroller oder andere hardware, die Sie haben die Kontrolle über. Windows hat eine MENGE Los und Sie haben sehr begrenzte Kontrolle und Transparenz in den proprietären code.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gut, ich bin immer verschiedene Anzahl von bis zu 100 Hz tatsächlich, mit einigen großen Abweichungen, aber in den meisten Fällen näher an der gesuchten Zahl (läuft XP SP3 mit neusten .NETTO-SPs).
System.Timer.Timer implementiert ist die Verwendung von System.Threading.Timer, so dass dies erklärt, warum Sie sehen, die gleichen Ergebnisse. Ich nehme an, dass der timer implementiert, der unter Verwendung einer Art von scheduling-Algorithmus etc. (es ist der interne Anruf, vielleicht auf der Suche am Rotor 2.0 könnte etwas Licht auf, es).
Ich würde vorschlagen, die Einführung einer Art timer mit einem anderen Faden (oder eine Kombination davon) Aufruf von Sleep und einen Rückruf. Nicht sicher über das Ergebnis, obwohl.
Sonst könnten Sie werfen Sie einen Blick auf multimedia-Timer (PInvoke).
Wenn Sie winmm.dll Sie können mehr CPU-Zeit, haben aber eine bessere Kontrolle.
Hier ist Ihr Beispiel so modifiziert, dass die winmm.dll Timer
Und hier ist die Ausgabe die ich bekomme:
Hoffe, das hilft.
Diese Klassen sind nicht vorgesehen für die Echtzeit-Nutzung und unterliegen dem dynamischen scheduling Natur von einem Betriebssystem wie Windows. Wenn Sie brauchen, real-time execution würden Sie wahrscheinlich wollen sich einige embedded-hardware. Ich bin mir nicht 100% sicher, aber ich denke .netcpu kann eine Echtzeit-version des kleineren .NET-runtime auf einem chip.
http://www.arm.com/markets/emerging_applications/armpp/8070.html
Natürlich - Sie brauchen, um zu bewerten, wie wichtig Genauigkeit der Intervalle gegeben sind, dass der code angehängt wird die Ausführung auf einem nicht-realtime-Betriebssystem. Es sei denn, dies ist natürlich eine rein Akademische Frage (in dem Fall - ja, es ist interessant! :P).
Es sieht aus wie Ihre tatsächliche timer-Frequenzen 63,9% Hz oder ganzzahligen vielfachen davon.
Dass würde bedeuten, einen timer-Auflösung von etwa 15 msec (oder ganzzahligen vielfachen therefof, d.h. 30 MS, 45 MS, etc.).
Diese, Timer, basierend auf ganzzahligen vielfachen von einem 'tick', zu erwarten ist (in DOS zum Beispiel die "tick" - Wert war 55 msec /18 Hz).
Ich weiß nicht, warum Ihr tick-Zählung ist 15.65 mec anstelle einer sogar 15 msec. Als ein experiment, was passiert, wenn Sie schlafen für mehrere msec innerhalb der timer-handler: vielleicht, wir werden sehen 15 msec zwischen Zecken und 0.65 MS in den timer-handler bei jedem tick?
Windows (und daher .NET läuft auf die Oberseite) ist ein präventiv multitasking-Betriebssystem. Alle angegebenen thread kann jederzeit beendet werden, durch einen anderen thread, und wenn die preempting thread nicht ordentlich benehmen, bekommen Sie keine Steuern zurück, wenn Sie es wollen oder müssen es.
Dass Sie in einer nussschale, ist, warum Sie nicht garantiert, um genaue Zeitangaben, und warum Windows und .NET ungeeignet sind Plattformen, die für bestimmte Arten von software. Wenn Leben in Gefahr sind, weil Sie nicht GENAU Steuern, wenn Sie es möchten, wählen Sie eine andere Plattform.
Wenn Sie brauchen, um den Sprung zu einer Echtzeit-Umgebung, die ich verwendet habe, RTX in der Vergangenheit, wenn deterministische Abtastung benötigt wurde (von einer benutzerdefinierten seriellen Gerät) und hatte sehr viel Glück mit ihm.
http://www.pharlap.com/rtx.htm
Hier ist eine schöne Umsetzung einer timer-multimedia timer
http://www.softwareinteractions.com/blog/2009/12/7/using-the-multimedia-timer-from-c.html
Es gibt eine Menge von Gründen, dass die timer-Frequenzen aus. Beispiel mit der hardware, der gleiche thread ist beschäftigt mit der weiteren Verarbeitung, und so weiter...
Wenn du mehr willst genau Zeit, die Verwendung der Stopwatch-Klasse im System.Diagnostics-namespace.
Teil des Problems ist, dass der Timer hat zwei Verzögerungen zu berücksichtigen. Dies kann variieren, je nachdem wie der timer implementiert im Betriebssystem.
Der timer hat eine gute Kontrolle von #1, aber fast keine Kontrolle mehr über die #2. Es kann ein signal an das Betriebssystem, dass Sie gerne wieder zu laufen, aber das OS ist kostenlos, um ihn zu aktivieren, wenn es fühlt sich an wie es.
Basierend auf Ihre Kommentare, sollten Sie sich nicht mit einer Schaltuhr. Sie sollten eine Schleife mit einer Stoppuhr zu überprüfen, das Intervall und ein spinlock, also verlieren Sie nicht das quantum.