2009-12-10 3 views
63

Welcher davon ist der schnellere/bessere?Eine Variable innerhalb oder außerhalb einer foreach-Schleife deklarieren: Was ist schneller/besser?

Dieses:

List<User> list = new List<User>(); 
User u; 

foreach (string s in l) 
{ 
    u = new User(); 
    u.Name = s; 
    list.Add(u); 
} 

Oder diese:

List<User> list = new List<User>(); 

foreach (string s in l) 
{ 
    User u = new User(); 
    u.Name = s; 
    list.Add(u); 
} 

Mein Neuling-Entwicklung von Fähigkeiten sagt mir, die erste ist besser, aber ein Freund von mir erzählt im falschen mich, konnte aber gib mir keinen guten Grund, warum der zweite besser ist.

Gibt es überhaupt einen Unterschied in der Leistung?

Antwort

77

Leistungsmäßig werden beide Beispiele zu derselben IL kompiliert, also gibt es keinen Unterschied.

Die zweite ist besser, weil es deutlicher Ihre Absicht ausdrückt, wenn u nur innerhalb der Schleife verwendet wird.

+9

anzumerken, dass es * * ist ein Unterschied, wenn die Variable durch einen Lambda-Ausdruck oder anonym Delegierten erfaßt wird; siehe [Äußere Variablenfalle] (http://stackoverflow.com/q/3416758). – dtb

+0

Können Sie erklären, warum beide in derselben IL kompiliert sind? Ich bin mir ziemlich sicher, dass C# keine variablen Deklarationen bis zur Spitze der Funktion hochhebt, wie es JavaScript tut. – styfle

+3

@styfle hier ist [die Antwort] (http://stackoverflow.com/questions/1884906/declaring-a-variable-inside-or-out-side-an-foreach-loop-which-is-faster-better#comment1785311_1884957) zu Ihre Frage. –

1

Die zweite ist besser. Sie möchten in jeder Iteration einen neuen Benutzer haben.

0

Es sollte keinen wahrnehmbaren Unterschied in der Leistung geben.

1

Technisch betrachtet, spart das erste Beispiel ein paar Nanosekunden, weil der Stapelrahmen nicht verschoben werden muss, um eine neue Variable zuzuweisen, aber das ist eine so kleine Menge an CPU-Zeit, dass Sie es nicht bemerken Der Compiler optimiert keine Unterschiede.

+0

Ich bin ziemlich sicher, dass die CLR nicht "eine neue Variable" bei jeder Iteration einer Schleife zuweisen. – dtb

+0

Nun, der Compiler kann das gut optimieren, aber Stack-Platz muss für alle Variablen in einer Schleife reserviert werden. Dies wäre implementierungsabhängig und eine Implementierung könnte einfach den Stapelrahmen gleich halten, während ein anderer (sagen wir Mono) den Stapel freigeben könnte, um ihn dann auf jeder Schleife neu zu erstellen. –

+11

Alle lokalen Variablen in einer Methode (auf oberster Ebene oder in einer Schleife verschachtelt) werden in Variablen auf Methodenebene in IL kompiliert. Der Platz für die Variablen wird vor der Ausführung der Methode zugewiesen, nicht wenn eine Verzweigung mit der Deklaration in C# erreicht wird. – dtb

6

Eine Deklaration führt nicht dazu, dass Code ausgeführt wird. Es handelt sich also nicht um ein Leistungsproblem.

Die zweite ist, was Sie meinen, und Sie sind weniger wahrscheinlich, einen dummen Fehler zu machen, wenn Sie es auf die zweite Art tun, also verwenden Sie das. Versuchen Sie immer Variablen im kleinstmöglichen Umfang zu deklarieren.

Und außerdem ist der bessere Weg ist Linq zu verwenden:

List<User> users = l.Select(name => new User{ Name = name }).ToList(); 
+2

Ich liebe die Zeile "Immer versuchen, Variablen im kleinstmöglichen Umfang zu deklarieren." Ich denke, eine einzelne Zeile kann die Frage sehr gut beantworten. – Manjoor

1

In diesem Szenario wird die zweite Version besser ist.

Wenn Sie nur auf den Wert im Rumpf der Iteration zugreifen müssen, wählen Sie im Allgemeinen die zweite Version. Auf der anderen Seite, wenn es einen Endzustand gibt, wird die Variable über den Körper der Schleife gehalten, dann deklariere dann die erste Version.

11

Auf jeden Fall der beste Weg, einen Konstruktor zu verwenden wäre, die einen Namen hat ... oder sonst ausnutzen geschweiften Klammer-Notation:

foreach (string s in l) 
{ 
    list.Add(new User(s)); 
} 

oder

foreach (string s in l) 
{ 
    list.Add(new User() { Name = s }); 
} 

oder noch besser, LINQ:

var list = l.Select(s => new User { Name = s}); 

Jetzt, während Ihr erstes Beispiel könnte, in einigen Fällen unperceptibly schneller sein, der zweite auf e ist besser, weil es lesbarer ist, und der Compiler kann die Variable verwerfen (und sie ganz weglassen), da sie nicht außerhalb des Bereichs foreach verwendet wird.

+4

Nekrophile Kommentar des Tages: "oder noch besser, LINQ". Sicher, es ist eine Codezeile, und das gibt uns als Entwickler ein gutes Gefühl. Aber die Vier-Zeilen-Version ist viel verständlicher und dadurch wartbar. –

+3

Kaum. Mit der LINQ-Version weiß ich, dass das, was ich mache, unveränderlich ist und über jedes Element funktioniert. – Tordek

3

Wenn Sie eine Frage zur Leistung haben, müssen Sie nur messen - führen Sie eine Schleife durch Ihren Test und geben Sie die Zeit ein.

Um Ihre Frage zu beantworten - ohne zu messen :-) oder Blick auf die generierte ilasm - keinen Unterschied in einer sinnvollen Anzahl von Iterationen nicht bemerkbar und die teuerste Operation in Ihrem Code ist wahrscheinlich die Benutzerzuweisung um ein paar Größenordnungen, so konzentrieren Sie sich auf Code Klarheit (wie Sie sollten im Allgemeinen) und gehen mit 2.

Oh, es ist spät und ich denke, ich versuche nur zu sagen, mach dir keine Sorgen über diese Art von Ding oder sich in Details wie diese verfangen.

K

+0

thx für den Tipp, ich denke, ich werde Zeit einige andere Sachen, über die ich auch woghle haben hehe: D – Marcus

+0

Wenn Sie weiter gehen mit Blick auf die Auswirkungen auf die Leistung, schauen Sie in die Verwendung eines Code-Profiler. Wenn nichts anderes, wird es Ihnen eine Vorstellung davon geben, welche Art von Code und Operationen am meisten Zeit benötigen. ProfileSharp und EqatecProfiler sind kostenlos und ausreichend für den Einstieg. –

Verwandte Themen