Wird der C # -Compiler Aufrufe einer Methode innerhalb einer Schleife optimieren?

8

Betrachten Sie den folgenden Code:

%Vor%

Wird der Compiler die Aufrufe von Test.OptionOne.ToString() optimieren oder wird er für jedes Element in der testValues -Auflistung aufgerufen?

    
Rat Salad 02.02.2016, 17:09
quelle

2 Antworten

8

Ihre Frage ist eine der Schleifen-Invarianten-Analyse - kann der Compiler einen Ausdruck in einer Schleife erkennen, die nicht vom Zustand der Schleife abhängt und keine Nebenwirkungen hat?

Es gibt gute Gründe zu hoffen, dass der Compiler beide Aussagen erfüllen könnte - der Compiler könnte schlau genug sein zu wissen, dass sich der Aufruf von ToString() in einer Enumeration nicht ändert; und das Aufrufen von ToString() in einer Aufzählung hat keine nennenswerten Nebenwirkungen.

Es könnte Gründe geben, warum der Compiler aktiv entscheiden würde, die Invariante nicht zu hissen - vielleicht ist das Aufrufen der Funktion etwas schneller als das Speichern einer zusätzlichen Variable auf dem Stack.

Die Frage läuft darauf hinaus, ob es tut .

Ich habe das folgende Programm mit VS2012 Targeting .NET 4.6 kompiliert und mit optimierten Optimierungen kompiliert. Es scheint, dass der Compiler nicht ausgewählt hat, die Invariante aus der Schleife zu heben:

%Vor%

Hier ist die rohe IL aus dem Programm, das ich mit ILSpy 2.3.1 erhalten habe. Beachten Sie den Aufruf von ToString() , genau in der Mitte der Schleife.

%Vor%

Ich bin auch neugierig geworden, ob der Laufzeit-JITer die Invariante hissen würde, aber es scheint auch nicht so zu sein. Ich habe den Code folgendermaßen geändert, um die Baugruppe sauberer zu machen:

%Vor%

Und dann VS-Debugger verwendet, um die Assembly zu erhalten, wobei darauf zu achten ist, dass VS den JITer optimieren ließ. Der Aufruf von ToString () wurde noch nicht ausgelöst:

%Vor%     
antiduh 02.02.2016, 17:26
quelle
1

Nein, aber Sie können die Komplexität erheblich reduzieren, indem Sie so etwas tun:

%Vor%

Die Suche nach Wörterbuchwerten hat eine Komplexität von O (1).

Ich denke, eine Alternative ist HashSet , wie Sie es getan haben nur Schlüssel. Eine interessante Frage und Antworten zum Aufbau einer HashSet aus einer Liste finden Sie hier .

[Bearbeiten] Nach Scotts Kommentar werde ich eine Option mit Hashset (auch in O (1)) einfügen:

%Vor%

Basierend auf der korrekten Beobachtung von btlog wird der Beispielcode für Duplikate fehlschlagen. Es kann umgangen werden entweder:

  • erstellt beim Abrufen von Daten direkt den HashSet (vermeiden Sie die Liste an erster Stelle)
  • Erhalte eine zweite Liste mit verschiedenen Werten, indem du Distinct verwendest

Der zweite Ansatz erhöht jedoch die Komplexität auf O (N)

    
Alexei 02.02.2016 17:17
quelle

Tags und Links