Ich habe überlegt, ob ich die Lazy<T>
Eigenschaften, um die Leistung meines eigenen Codes zu verbessern (und um etwas mehr darüber zu lernen). Ich kam hier auf der Suche nach Antworten über, wenn es zu verwenden, aber es scheint, dass überall, wo ich gehe gibt es Phrasen wie:
Verwenden Sie die faule Initialisierung, um die Erstellung eines großen oder ressourcenintensiven Objekts oder der Ausführung einer ressourcenintensiven Aufgabe zu verschieben, insbesondere wenn eine solche Erstellung oder Ausführung nicht während der Lebensdauer des Programms.
von MSDN Lazy<T> Klasse
Ich bin ein wenig verwirrt, weil ich nicht sicher bin, wo ich die Grenze ziehen soll. Ich betrachte zum Beispiel die lineare Interpolation als eine ziemlich schnelle Berechnung, aber wenn ich sie nicht durchführen muss, kann ich sie dann mit Hilfe der trägen Initialisierung vermeiden und ist sie es wert?
Schließlich beschloss ich, meinen eigenen Test durchzuführen, und dachte, ich würde die Ergebnisse hier mitteilen. Leider bin ich kein wirklicher Experte für diese Art von Tests und freue mich daher über Kommentare mit Verbesserungsvorschlägen.
Beschreibung
In meinem Fall war ich besonders daran interessiert, zu sehen, ob Lazy Properties helfen könnte, einen Teil meines Codes zu verbessern, der eine Menge Interpolationen durchführt (die meisten davon sind ungenutzt), und so habe ich einen Test erstellt, der 3 Ansätze vergleicht.
Ich habe für jeden Ansatz eine eigene Testklasse mit 20 Testeigenschaften (nennen wir sie t-properties) erstellt.
- GetInterp Klasse: Führt jedes Mal eine lineare Interpolation durch, wenn eine t-Eigenschaft erhalten wird.
- InitInterp Klasse: Initialisiert die t-Eigenschaften, indem die lineare Interpolation für jede Eigenschaft im Konstruktor ausgeführt wird. Die Funktion get gibt einfach einen Double zurück.
- InitLazy-Klasse: Richtet die t-Eigenschaften als Lazy-Eigenschaften ein, so dass die lineare Interpolation einmal ausgeführt wird, wenn die Eigenschaft zum ersten Mal abgerufen wird. Spätere Abfragen sollten einfach einen bereits berechneten Double zurückgeben.
Die Testergebnisse werden in ms gemessen und sind der Durchschnitt von 50 Instanziierungen oder 20 Property Gets. Jeder Test wurde dann 5 Mal durchgeführt.
Test 1 Ergebnisse: Instanziierung (Durchschnitt von 50 Instanziierungen)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.005668 0.005722 0.006704 0.006652 0.005572 0.0060636 6.72
InitInterp 0.08481 0.084908 0.099328 0.098626 0.083774 0.0902892 100.00
InitLazy 0.058436 0.05891 0.068046 0.068108 0.060648 0.0628296 69.59
Test 2 Ergebnisse: First Get (Durchschnitt von 20 Property Gets)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.263 0.268725 0.31373 0.263745 0.279675 0.277775 54.38
InitInterp 0.16316 0.161845 0.18675 0.163535 0.173625 0.169783 33.24
InitLazy 0.46932 0.55299 0.54726 0.47878 0.505635 0.510797 100.00
Test 3 Ergebnisse: Second Get (Durchschnitt von 20 Property Gets)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.08184 0.129325 0.112035 0.097575 0.098695 0.103894 85.30
InitInterp 0.102755 0.128865 0.111335 0.10137 0.106045 0.110074 90.37
InitLazy 0.19603 0.105715 0.107975 0.10034 0.098935 0.121799 100.00
Beobachtungen
GetInterp
ist erwartungsgemäß am schnellsten zu instanziieren, da es nichts tut. InitLazy
ist schneller zu instanziieren als InitInterp
was darauf hindeutet, dass der Overhead beim Einrichten von "Lazy Properties" schneller ist als meine lineare Interpolationsberechnung. Allerdings bin ich hier ein wenig verwirrt, weil InitInterp
sollte 20 lineare Interpolationen durchführen (um seine t-Eigenschaften einzurichten), benötigt aber nur 0,09 ms zum Instanziieren (Test 1), verglichen mit GetInterp
was beim ersten Mal (Test 2) 0,28 ms und beim zweiten Mal (Test 3) 0,1 ms für eine einzige lineare Interpolation benötigt.
Es braucht InitLazy
fast 2 mal länger als GetInterp
um eine Eigenschaft beim ersten Mal zu erhalten, während InitInterp
ist die schnellste, weil sie ihre Eigenschaften während der Instanziierung auffüllt. (Zumindest sollte es das tun, aber warum war das Ergebnis der Instanziierung so viel schneller als eine einfache lineare Interpolation? Wann genau führt es diese Interpolationen durch?)
Leider sieht es so aus, als ob in meinen Tests eine automatische Code-Optimierung durchgeführt wird. Es sollte dauern GetInterp
die gleiche Zeit, um eine Eigenschaft beim ersten Mal zu erhalten, wie beim zweiten Mal, aber es wird als mehr als 2x schneller angezeigt. Es sieht so aus, als ob sich diese Optimierung auch auf die anderen Klassen auswirkt, da sie alle etwa die gleiche Zeit für Test 3 benötigen. Solche Optimierungen können jedoch auch in meinem eigenen Produktionscode stattfinden, was ebenfalls ein wichtiger Aspekt sein kann.
Schlussfolgerungen
Während einige Ergebnisse den Erwartungen entsprechen, gibt es auch einige sehr interessante unerwartete Ergebnisse, die wahrscheinlich auf Code-Optimierungen zurückzuführen sind. Selbst bei Klassen, die im Konstruktor viel Arbeit zu machen scheinen, zeigen die Ergebnisse der Instanziierung, dass sie im Vergleich zum Erhalt einer doppelten Eigenschaft sehr schnell erstellt werden können. Während Experten auf diesem Gebiet vielleicht in der Lage sind, sich dazu zu äußern und die Sache genauer zu untersuchen, habe ich persönlich das Gefühl, dass ich diesen Test noch einmal durchführen muss, allerdings mit meinem Produktionscode, um zu untersuchen, welche Art von Optimierungen auch dort stattfinden könnten. Ich erwarte jedoch, dass InitInterp
könnte der richtige Weg sein.