Ich habe meine Hausaufgaben gemacht und wiederholte Versicherungen, dass es keinen Unterschied in der Leistung macht, ob Sie Ihre Variablen innerhalb oder außerhalb Ihrer for-Schleife deklarieren, und es tatsächlich auf die gleiche MSIL kompiliert. Aber ich habe trotzdem damit herumgespielt und festgestellt, dass das Verschieben der Variablendeklarationen innerhalb der Schleife tatsächlich zu einem beträchtlichen und konsistenten Leistungsgewinn führt.Können in einer for-Schleife deklarierte Variablen die Leistung der Schleife beeinflussen?
Ich habe eine kleine Konsole Testklasse geschrieben, um diesen Effekt zu messen. Ich initialisiere ein statisches double[]
Array Elemente, und zwei Methoden führen Schleifenoperationen darauf aus und schreiben die Ergebnisse in einen statischen double[]
Array Puffer. Ursprünglich waren meine Methoden diejenigen, mit denen ich den Unterschied bemerkte, nämlich die Größenberechnung einer komplexen Zahl. Führt man diese für ein Array von 1000000 für 100 mal, artikel, bekam ich konsistent niedrigere Laufzeiten für die, in denen die Variablen (6 double
Variablen) innerhalb der Schleife waren: zB 32,83 ± 0,64 ms v 43 , 24 ± 0,45 ms bei einer älteren Konfiguration mit Intel Core 2 Duo bei 2,66 GHz. Ich habe versucht, sie in anderer Reihenfolge auszuführen, aber das hat die Ergebnisse nicht beeinflusst.
static void Square1()
{
double x;
for (int i = 0; i < buffer.Length; i++) {
x = items[i];
buffer[i] = x * x;
}
}
static void Square2()
{
for (int i = 0; i < buffer.Length; i++) {
double x;
x = items[i];
buffer[i] = x * x;
}
}
Mit diesen kamen die Ergebnisse aus den anderen Weg: weit von einem minimalen Arbeitsbeispiel und getestet zwei viel einfachere Methoden
Dann erkannte ich, dass die Größe einer komplexen Zahl Berechnung erklärt die Variable außerhalb der Schleife schien günstiger zu sein: 7,07 ± 0,43 ms für Square1()
v 12,07 ± 0,51 ms für Square2()
.
Ich bin nicht vertraut mit ILDASM, aber ich habe die beiden Methoden zerlegt, und der einzige Unterschied scheint die Initialisierung der lokalen Variablen zu sein:
.locals init ([0] float64 x,
[1] int32 i,
[2] bool CS$4$0000)
in Square1()
v
.locals init ([0] int32 i,
[1] float64 x,
[2] bool CS$4$0000)
in Square2()
. In Übereinstimmung damit, was ist stloc.1
in einem ist stloc.0
in dem anderen, und umgekehrt. In der längeren komplexen Betragsberechnung MSIL-Codes sogar die Codegröße unterschieden und ich sah stloc.s i
in der externen Deklaration Code, wo es stloc.0
im internen Deklarationscode war.
Also wie kann das sein? Betrachte ich etwas oder ist es ein wirklicher Effekt? Wenn dies der Fall ist, kann dies die Leistungsfähigkeit von langen Schleifen erheblich beeinflussen, daher denke ich, dass es eine Diskussion verdient.
Ihre Gedanken werden sehr geschätzt.
EDIT: Die eine Sache, die ich übersehen habe, war, es auf mehreren Computern vor dem Posten zu testen. Ich habe es jetzt auf einem i5 ausgeführt und die Ergebnisse sind fast identisch für die beiden Methoden. Ich entschuldige mich dafür, dass ich eine solche irreführende Bemerkung gepostet habe.
Gute Untersuchung, Sie verdienen sicher eine Aufwertung. – NicoRiff
@NicoRiff: In der Tat, es ist eine sehr gut geschriebene Frage. (Leider denke ich, dass die Antwort trivial ist.) – Bathsheba
Ich kann nicht auf @ JonSkeet Antwort auf diese – NicoRiff