Die Geschichte dahinter
Manchmal lernt man in .NET etwas Neues kennen und fragt sich danach vor allem, wie man es all die Jahre übersehen konnte. Heute war das bei mir der PeriodicTimer
Timer sind in .NET nun wirklich nichts Neues. Mit System.Threading.Timer, System.Timers.Timer und dem guten alten System.Windows.Forms.Timer gibt es bereits eine erstaunliche Auswahl an Möglichkeiten, Dinge regelmässig passieren zu lassen. Und trotzdem stand plötzlich noch einer vor der Tür: PeriodicTimer.
Eigentlich eine angenehm moderne Variante. Kein klassischer Callback, kein Event, sondern etwas, das sich sehr schön in die Welt von async und await einfügt. Damit hätte die Geschichte auch schon wieder vorbei sein können. Ich hätte sagen können: Wieder etwas gelernt. Und anschliessend etwas Sinnvolles tun.
Das wäre vernünftig gewesen.
Stattdessen entstand die Frage, was eigentlich passiert, wenn man die verschiedenen Generationen von .NET-Zeitmessung miteinander bekannt macht. Wenn wir schon einen modernen PeriodicTimer haben, könnte man schliesslich auch noch einen klassischen Timer dazunehmen. Und wenn wir bereits dabei sind, verschiedene Epochen der Softwareentwicklung miteinander zu vermischen, darf natürlich ein alter Bekannter nicht fehlen: goto.
Nicht weil man es braucht, sondern weil es da ist.
Damit war aus einem kleinen Experiment langsam etwas geworden, das man mit etwas Wohlwollen als Zustandsmaschine bezeichnen könnte. Mit weniger Wohlwollen wahrscheinlich eher als Unfall.
Irgendeine Logik musste das Ganze natürlich trotzdem bekommen. Und genau an dieser Stelle kam ein völlig anderes Thema ins Spiel, das mit Timern eigentlich überhaupt nichts zu tun hat: das Doomsday-Phänomen.
Bestimmte leicht merkbare Daten eines Jahres fallen immer auf denselben Wochentag. Dazu gehören unter anderem 4.4., 6.6., 8.8., 10.10. und 12.12. Das ist mathematisch durchaus interessant. Für einen Heartbeat-Mechanismus ist es dagegen vollkommen unnötig.
Also selbstverständlich perfekt geeignet.
Ein Zufallsgenerator durfte nun eines dieser Daten auswählen, anschliessend wurde der Wochentag verglichen und daraus der Startwert für den Heartbeat bestimmt. Das Ergebnis dieser beeindruckenden Konstruktion ist zuverlässig: 1
Man könnte diesen Wert natürlich auch direkt hinschreiben. Aber wo bliebe dann die Wissenschaft?
Damit waren irgendwann moderne asynchrone Programmierung, klassische Timer, ein goto aus vergangenen Zeiten und ein kalendarisches Phänomen miteinander verbunden. Eigentlich Dinge, die sich vermutlich nie kennenlernen sollten.
Das Überraschende daran war nicht, dass der Code kompliziert aussah. Das Überraschende war:
Er funktionierte.
Im Log lief der Ablauf sauber Sekunde für Sekunde durch. Delay, Periodic, Callback, noch ein Callback, wieder Periodic, noch ein Callback und anschliessend zurück zum Anfang. Fast wie ein Schweizer Uhrwerk.
Nur dass ein Schweizer Uhrmacher vermutlich spätestens beim ersten goto seine Werkzeugkiste genommen und den Raum verlassen hätte.
Fazit
Niemand versteht die Logik. Sie gilt daher als stabil.
Aus einem harmlosen PeriodicTimer wurde ein Ausflug durch mehrere Generationen von .NET, etwas goto-Nostalgie und ein völlig unnötig eingebautes Doomsday-Phänomen. Etwas Neues gelernt, etwas Altes wieder ausgegraben und dabei erstaunlich viel Spass gehabt.
Der Code dazu
Wer sich den kompletten speziellen Heartbeat-Mechanismus ansehen möchte, findet hier den vollständigen Code:
Ausgabe: [20:31:14 DBG] Timer[Delay]: Second=14 [20:31:15 DBG] Timer[Periodic]: Second=15 [20:31:16 DBG] Timer[Callback][1]: Second=16 [20:31:17 DBG] Timer[Callback][2]: Second=17 [20:31:18 DBG] Timer[Periodic]: Second=18 [20:31:19 DBG] Timer[Callback][3]: Second=19 [20:31:20 DBG] Timer[Delay]: Second=20 [20:31:21 DBG] Timer[Periodic]: Second=21 [20:31:22 DBG] Timer[Callback][1]: Second=22 [20:31:23 DBG] Timer[Callback][2]: Second=23 [20:31:24 DBG] Timer[Periodic]: Second=24 [20:31:25 DBG] Timer[Callback][3]: Second=25 [20:31:26 DBG] Timer[Delay]: Second=26 [20:31:27 DBG] Timer[Periodic]: Second=27 [20:31:28 DBG] Timer[Callback][1]: Second=28 [20:31:29 DBG] Timer[Callback][2]: Second=29 [20:31:30 DBG] Timer[Periodic]: Second=30 [20:31:31 DBG] Timer[Callback][3]: Second=31 [20:31:33 DBG] Timer[Delay]: Second=33 [20:31:34 DBG] Timer[Periodic]: Second=34
Hinterlasse einen Kommentar