Bei einem anderen Test stellte sich heraus, dass der Algorithmus mit den Performance-Verbesserungen „richtiger“ rechnete als die vorherige Implementation. Der Fehler hatte zwar keine Auswirkungen, da die Geräte den Wert nicht auswerten sollten, könnte aber bei einem Fehler auf der Geräteseite zu unerwartetem Verhalten führen.
Schlagwort-Archive: Performance
Reflektion KW 47
Wir werden nun die Verbesserungen nun in sauberen Code umsetzen und mitsamt den zusätzlichen neuen Features eines Zwischen-Release erzeugen. Dies wird dann eine intensive Testphase zur Folge haben um den Release plangemäss ausliefern zu können.
Reflektion KW 46
Währenddessen konnte ich einige kleine Tasks, die ‚vor sich hin dümpelten‘, in dieser Woche abschliessen, so dass ich nächste Woche bei der Performance-Optimierung mithelfen kann.
Reflektion KW 45
Das Review wurde auf zwei Teile mit unterschiedlichen Themen aufgeteilt. Die Stakeholder wurden entsprechend eingeladen und, wie in der Retrospektive der Woche 42 beschrieben, über die zu erwartenden Ergebnisse vorab informiert. Dadurch konnten die Diskussionen in der nötigen Tiefe abgehalten werden ohne dass die Hälfte der Stakeholder nicht an dem Thema interessiert gewesen wäre.
Im Rahmen des einen Review kam zum Vorschein, dass nicht nur die Dokumentation angepasst werden sollte sondern auch die daraus folgenden nötigen Anpassungen kommuniziert werden sollten. Es stellt sich hier die Frage, ob es sich dabei um eine Hol- oder eine Bring-Schuld handelt. Aus meiner Sicht sollten, wenn bekannt ist dass das andere Team die Funktionalität zur Zeit implementiert, Änderungen dem anderen Team auch mitgeteilt werden und nicht darauf gehofft werden, dass schon nachgefragt wird.
Reflektion KW 44
Diese Woche schwebte eine „Altlast“ des vorherigen Releases wie ein Damoklesschwert über dem Team: Die Performance-Probleme bei grossen Mengengerüsten waren bekannt und wurden auch immer offen kommuniziert. Da nun aber ein Auftrag mit einem grossen Mengengerüst ansteht wurde das Management nervös und dieses Problem muss nun sofort angegangen werden. Zwei bis drei Team-Mitglieder werden sich nun diesem Problem widmen während der Rest am neuen Release weiterarbeitet.
Während des „normalen“ Tagesgeschäftes zeigte sich wieder einmal, dass der Wert einer Dokumentation sinkt, wenn sie nicht aktuell gehalten wird. Besonders wenn es sich um die Definition eines Protokolls handelt, da normalerweise für die Kommunikation zwei Parteien nötig sind. Wenn nun Fehler oder Unklarheiten in der Dokumentation beim Implementieren auftauchen, diese aber nicht korrigiert werden, muss auf der Gegenseite dieselbe Lernkurve nochmals durchlaufen werden.
Rekursiv vs. Iterativ revisited
Im KaffeeKlatsch vom November 2012 habe ich einen interessanten Artikel über die Fakultätsberechnung gelesen.
Dies hat mich dazu bewogen, meine eigene Untersuchung nochmals hervorzuholen und zu überprüfen.
Ich habe dabei, wie im KaffeeKlatsch-Artikel, den Datentyp BigInteger (Namespace System.Numerics, Assembly System.Numerics.dll) eingesetzt. Ich habe auch noch die Schlaufe verkürzt, damit ich nicht so lange auf das Resultat warten muss. Weitere Optimierungen habe ich nicht vorgenommen.
Hier das Ergebnis:
-------------------------------------------
10!
Recursive: 00:00:00.1390079
Iterative: 00:00:00.1190069
100!
Recursive: 00:00:01.9631122
Iterative: 00:00:01.7991029
1000!
Recursive: 00:00:51.7689611
Iterative: 00:00:43.3274782
10000!
Process is terminated due to StackOverflowException.
Es sind zwei Dinge ersichtlich:
- Die iterative Implementierung ist immer noch schneller als die rekursive, aber der Unterschied ist nicht mehr so gross. Dies dürfte darauf zurückzuführen sein, dass die eigentliche Berechnung (das Multiplizieren) mit dem BigInteger mehr Aufwand verursacht und der Overhead des rekursiven Aufrufs nicht mehr so ins Gewicht fällt. Dafür spricht auch, dass ich die Wiederholungszahl verkleinern musste.
- Es wird schon früher eine StackOverflowException geworfen. Dies dürfte auch daran liegen, dass mit dem BigInteger noch weitere Funktionsaufrufe einhergehen, die auf dem Stack gespeichert werden.
Fazit:
Meine erste Untersuchung wurde (ansatzweise) bestätigt, die Vereinfachung mit dem akzeptieren eines falschen Resultates mit dem int hat aber das Ergebnis stärker beeinflusst, als ich das vermutet hatte.
Rekursiv vs. Iterativ
In der dotnetpro 8/2011 hat Ralp Westphal im Artikel „Aus Baum mach Fluss“ zum Einstieg die Fakultätsberechnung in der rekursiven und in der iterativen Variante gezeigt. Seiner Meinung nach ist die iterative Variante einfacher zu verstehen, besonders für nicht-Mathematiker.
Ich fragte mich dann, welche Variante ist für den Computer einfacher zu verstehen, d.h. welche Variante ist performanter? Oder ist es egal, optimiert der Compiler schon so weit, dass beide Varianten in etwa gleich schnell sind?
Ich habe ein kleines Programm geschrieben, dass die Fakultät für verschiedene Werte mehrmals berechnet, um messbare Werte zu erhalten.
Hier die Resultate:
---------------------------------
10!
Recursive: 00:00:00.0390023
Iterative: 00:00:00.0220012
100!
Recursive: 00:00:00.2940168
Iterative: 00:00:00.1720099
1000!
Recursive: 00:00:02.5131437
Iterative: 00:00:01.0270588
10000!
Recursive: 00:00:25.0624335
Iterative: 00:00:09.4535407
Die rekursive Variante braucht also etwa 2.5 mal so lang wie die iterative. Und bei grossen Fakultäten kommt noch ein weiteres Problem hinzu: Es wird eine StackOverflowException geworfen, da jeder Rekursionsschritt einen Funktionsaufruf zur Folge hat, der einen Teil des Stacks beansprucht.
Fazit:
Der iterative Ansatz ist (mindestens in diesem Fall) auch für den Computer „einfacher zu verstehen“. Neben der besseren Performance ist aber auch die gebannte Gefahr des Stack Overflows ein wichtiger Grund, die iterative Varinate vorzuziehen.