Wie teuer ist .NET Reflection?

210

Ich höre ständig, wie schlecht Reflexion zu verwenden ist. Während ich Reflexionen im Allgemeinen vermeide und selten Situationen finde, in denen es unmöglich ist, mein Problem ohne sie zu lösen, habe ich mich gefragt ...

Haben Sie für diejenigen, die Reflexion in Anwendungen verwendet haben, Leistungstreffer gemessen und ist das wirklich so schlimm?

Dan Herbert
quelle
Vielleicht möchten Sie auch diese Frage überprüfen. stackoverflow.com/questions/224232/…
smaclell
1
Verwenden Sie die API unter schnellerflect.codeplex.com. Es beschleunigt die Reflexion um das 500-fache für Getter / Setter / Invoker und einige andere Dinge. Quelle und Informationen darüber, wie es funktioniert, gibt es auch, wenn Sie es erweitern müssen.
Brandon Moore
3
Wie werden diese Informationen im Jahr 2014 ausgecheckt? Hat sich in diesen 4 Jahren etwas geändert?
Arnthor
1
Die einfache Aufgabe, einer Instanzeigenschaft einen Wert zuzuweisen, ist mit Reflection (PropertyInfo.SetValue (Instanz, Wert)) ungefähr 150-mal langsamer als mit einfacher Codierung (instance.property = value). Dies ist in .NET 4.0
Thanasis Ioannidis

Antworten:

130

Es ist. Aber das hängt davon ab, was Sie versuchen zu tun.

Ich verwende Reflection, um Assemblys (Plugins) dynamisch zu laden, und die Leistungsbeeinträchtigung ist kein Problem, da der Vorgang beim Starten der Anwendung ausgeführt wird.

Wenn Sie jedoch in einer Reihe verschachtelter Schleifen mit jeweils Reflexionsaufrufen reflektieren, sollten Sie Ihren Code erneut aufrufen :)

Für "ein paar Mal" -Operationen ist die Reflexion vollkommen akzeptabel und Sie werden keine Verzögerung oder Probleme damit bemerken. Es ist ein sehr leistungsfähiger Mechanismus und wird sogar von .NET verwendet, daher verstehe ich nicht, warum Sie es nicht ausprobieren sollten.

Martin Marconcini
quelle
Ich habe Reflection verwendet, um die Methode abzurufen, den Klassennamen der aktuellen Methode, um den Fehler in try-catch zu protokollieren. Grundsätzlich, um zu vermeiden, dass der Funktionsname während des Protokollierungsfehlers fest codiert wird. Muss ich mir Sorgen machen?
Sangram Nandkhile
@ Sangram nein, das ist in Ordnung
Karthik AMR
@ Sangram nein, es sei denn, Sie haben viele Fehler, die ständig abgefangen werden müssen, was dann ein anderes Problem sein sollte :)
Martin Marconcini
5
@Sangram Während die Reflexionsleistung in Ihrem Fall nicht das Problem sein sollte, scheint es, als würden Sie versuchen, das, was einfache alte Ausnahmen bieten, auf eine viel elegantere Art und Weise neu zu implementieren ...
Jacek Gorgoń
152

Jeff Richter zeigt in seinem Vortrag The Performance of Everyday Things , dass das Aufrufen einer Methode durch Reflexion etwa 1000-mal langsamer ist als das normale Aufrufen.

Jeffs Tipp: Wenn Sie die Methode mehrmals aufrufen müssen, verwenden Sie Reflection einmal, um sie zu finden, weisen Sie sie dann einem Delegaten zu und rufen Sie den Delegaten auf.

ESRogs
quelle
18
Ich habe auch an Devscovery teilgenommen und stimme diesen Ergebnissen für .NET 3.5 zu. Das Neukompilieren des Devscovery-Leistungsbenchmarkprogramms für .NET 4 zeigt eine massive Verbesserung! Die Kosten sinken auf das 100-fache. Die Verwendung von Reflection für typeof () - Lookups ist zwischen .NET 3.5 und .NET 4 unverändert.
John Wigger
61

Die Reflexionsleistung hängt von der Implementierung ab (wiederholte Aufrufe sollten zwischengespeichert werden, z entity.GetType().GetProperty("PropName"). B. :) . Da der größte Teil der Reflexion, die ich täglich sehe, zum Auffüllen von Entitäten aus Datenlesern oder anderen Strukturen vom Repository-Typ verwendet wird, habe ich beschlossen, die Leistung speziell anhand der Reflexion zu bewerten, wenn sie zum Abrufen oder Festlegen von Objekteigenschaften verwendet wird.

Ich habe einen Test entwickelt, der meiner Meinung nach fair ist, da er alle sich wiederholenden Aufrufe und nur den tatsächlichen SetValue- oder GetValue-Aufruf zwischenspeichert. Der gesamte Quellcode für den Leistungstest befindet sich in bitbucket unter: https://bitbucket.org/grenade/accessortest . Kontrolle ist willkommen und erwünscht.

Ich bin zu dem Schluss gekommen, dass das Entfernen von Reflexionen in einer Datenzugriffsschicht, die weniger als 100.000 Zeilen zu einem Zeitpunkt zurückgibt, an dem die Reflexionsimplementierung gut durchgeführt wird, nicht praktikabel ist und keine merklichen Leistungsverbesserungen bietet.

Zeitdiagramm (y) gegen Anzahl der bestückten Entitäten (x)

Die obige Grafik zeigt die Ausgabe meines kleinen Benchmarks und zeigt, dass Mechanismen, die die Reflexion übertreffen, dies erst nach der 100.000-Zyklen-Marke merklich tun. Die meisten DALs geben jeweils nur einige hundert oder vielleicht Tausende von Zeilen zurück, und auf diesen Ebenen funktioniert die Reflexion einwandfrei.

Granate
quelle
9
Nicht unbedingt. Ihre DAL-Conversions beziehen sich möglicherweise nur auf einige tausend Elemente. Multiplizieren Sie dies jedoch mit gleichzeitigen Benutzern, die Ihre Anwendung verwenden (wenn es sich um ein Web handelt), und es summiert sich möglicherweise so, als würden Sie Millionen Elemente konvertieren. Wenn eine bestimmte Methode 100-mal langsamer ist, ist sie bei kleinen und großen Sets umso langsamer. Langsamer ist langsamer.
Robert Koritnik
@ RobertKoritnik Das setzt voraus, dass die Webmethoden auf Ihrem Server nicht asynchron sind
Kurren
Die @kurren-Asynchronität wirkt sich nicht auf die Reflexion aus, sondern auf die Serverressourcen. Asynchrone Webmethoden können natürlich mehr Benutzer bedienen, aber die Reflexion ist immer noch langsam. Und Reflexion an sich AFAIK ist sowieso ein synchroner Prozess. Das Abrufen von Daten ist dagegen die einzige Rolle, die beim asynchronen Design eine gute Rolle spielt.
Robert Koritnik
3
Was ist die Hyper-Methode in der Tabelle? Wie unterscheidet es sich von Reflector?
Bryan Legend
Ich hätte auf diesen @ LoneCoder verweisen
Granate
14

Wenn Sie nicht in einer Schleife sind, machen Sie sich darüber keine Sorgen.

David Plumpton
quelle
12

Meine relevanteste Erfahrung war das Schreiben von Code, um zwei beliebige Datenentitäten desselben Typs in einem großen Objektmodell in Bezug auf die Eigenschaften zu vergleichen. Habe es zum Laufen gebracht, es ausprobiert, bin offensichtlich wie ein Hund gelaufen.

Ich war verzweifelt und erkannte dann über Nacht, dass ich ohne Änderung der Logik denselben Algorithmus verwenden konnte, um automatisch Methoden für den Vergleich zu generieren, aber statisch auf die Eigenschaften zuzugreifen. Es dauerte überhaupt keine Zeit, den Code für diesen Zweck anzupassen, und ich hatte die Möglichkeit, Entitäten mit statischem Code zu vergleichen, der auf Knopfdruck aktualisiert werden konnte, wenn sich das Objektmodell änderte.

Mein Punkt ist: In Gesprächen mit Kollegen, seit ich mehrmals darauf hingewiesen habe, dass ihre Verwendung von Reflektion darin bestehen könnte, Code automatisch zu generieren, um Laufzeitoperationen zu kompilieren, anstatt sie auszuführen, und dies ist oft eine Überlegung wert.

Gaz
quelle
Angesichts der Tatsache, dass Visual Studio eine hervorragende Vorlagenunterstützung bietet, ist es eine praktische Möglichkeit, die Codegenerierung zu verwenden
Sebastian
12

Nicht massiv. Ich hatte noch nie ein Problem damit in der Desktop-Entwicklung, es sei denn, Sie verwenden es, wie Martin feststellt, an einem dummen Ort. Ich habe gehört, dass viele Leute völlig irrationale Befürchtungen hinsichtlich der Leistung bei der Desktop-Entwicklung haben.

Im Compact Framework (in dem ich normalerweise bin) ist es jedoch ziemlich anathema und sollte in den meisten Fällen wie die Pest vermieden werden. Ich kann immer noch selten damit durchkommen, aber ich muss sehr vorsichtig mit der Anwendung sein, die viel weniger Spaß macht. :((

Streit
quelle
5
+1, um mir ein neues Wort beizubringen: Anathema. Auch zur Erwähnung irrationaler Ängste. Ich fürchte Programmierer, die irrational fürchten - es zeigt, dass sie nicht wirklich wissen, was sie tun, und sich nur darauf stützen, was andere ihnen sagen. Husten Frachtkult Husten
Niesen
1
Ahhhh Frachtkult. Jetzt gibt es ein gutes Beispiel für merkwürdiges menschliches Verhalten.
Quibblesome
10

Es ist schon schlimm genug, dass Sie sich Sorgen machen müssen, selbst wenn die .NET-Bibliotheken intern über leistungskritischen Code nachdenken.

Das folgende Beispiel ist veraltet - zu der Zeit (2008) wahr, aber in neueren CLR-Versionen längst behoben. Reflexion im Allgemeinen ist jedoch immer noch etwas kostspielig!

Beispiel: Sie sollten niemals ein Mitglied verwenden, das als "Objekt" in einer Lock (C #) / SyncLock (VB.NET) -Anweisung in Hochleistungscode deklariert ist. Warum? Da die CLR einen Werttyp nicht sperren kann, muss sie zur Laufzeit eine Reflexionstypprüfung durchführen, um festzustellen, ob Ihr Objekt tatsächlich ein Werttyp anstelle eines Referenztyps ist.

McKenzieG1
quelle
13
Um fair zu sein, ist eine Reflexionsprüfung schnell.
Jimmy
1
Sollten Sie für einen solchen "leistungskritischen Code" zunächst wirklich .NET verwenden?
Seph
1
@Seph: Dynamische / Reflexionsteile von .NET, Nr. Aber übliches C # /. NET, warum nicht? C ++ vs C # -Beschleunigungen sind auf Anwendungsebene marginal (C ++ ist bei intensiven mathematischen Routinen immer noch einige% schneller). Und ich
vermute,
Ein Boxed-Value-Typ (dh ein Objekt) kann gesperrt werden. @BryceWagner ist korrekt.
Geflügel
1
Um fair zu sein (für mich), ist es genauer zu sagen, dass die Antwort "veraltet" ist und nicht "einfacher Unsinn". Meine Bemerkungen zum Verhalten von lock (obj) waren zum Zeitpunkt der Erstellung korrekt, aber das implementierungsspezifische Verhalten der CLR ist längst vorbei.
McKenzieG1
5

Wie bei allen Dingen in der Programmierung müssen Sie die Leistungskosten mit den erzielten Vorteilen in Einklang bringen. Reflexion ist ein unschätzbares Werkzeug, wenn sie mit Sorgfalt verwendet wird. Ich habe eine O / R-Zuordnungsbibliothek in C # erstellt, in der die Bindungen mithilfe von Reflektion erstellt wurden. Das hat fantastisch gut funktioniert. Der größte Teil des Reflexionscodes wurde nur einmal ausgeführt, sodass jeder Leistungseinbruch recht gering war, aber die Vorteile waren groß. Wenn ich einen neuen Fandangled-Sortieralgorithmus schreiben würde, würde ich wahrscheinlich keine Reflexion verwenden, da er wahrscheinlich schlecht skaliert.

Ich schätze, dass ich Ihre Frage hier nicht genau beantwortet habe. Mein Punkt ist, dass es nicht wirklich wichtig ist. Verwenden Sie gegebenenfalls Reflexion. Es ist nur eine weitere Sprachfunktion, die Sie lernen müssen, wie und wann Sie sie verwenden sollen.

Mike Thompson
quelle
3

Reflexion kann spürbare Auswirkungen auf die Leistung haben, wenn Sie sie für die häufige Objekterstellung verwenden. Ich habe eine Anwendung entwickelt, die auf dem Composite UI Application Block basiert und stark auf Reflexion beruht. Es gab einen merklichen Leistungsabfall im Zusammenhang mit der Objekterstellung durch Reflexion.

In den meisten Fällen gibt es jedoch keine Probleme mit der Verwendung von Reflexionen. Wenn Sie nur eine Baugruppe inspizieren müssen, würde ich Mono.Cecil empfehlen, das sehr leicht und schnell ist

aku
quelle
3

Die Reflexion ist kostspielig, da die Laufzeit viele Überprüfungen durchführen muss, wenn Sie eine Methode anfordern, die einer Liste von Parametern entspricht. Irgendwo tief im Inneren existiert Code, der alle Methoden für einen Typ durchläuft, seine Sichtbarkeit überprüft, den Rückgabetyp überprüft und auch den Typ jedes einzelnen Parameters überprüft. All dieses Zeug kostet Zeit.

Wenn Sie diese Methode intern ausführen, gibt es Code, der beispielsweise überprüft, ob Sie eine kompatible Liste von Parametern übergeben haben, bevor Sie die eigentliche Zielmethode ausführen.

Wenn möglich, wird immer empfohlen, das Methodenhandle zwischenzuspeichern, wenn es in Zukunft kontinuierlich wiederverwendet werden soll. Wie bei allen guten Programmiertipps ist es oft sinnvoll, sich nicht zu wiederholen. In diesem Fall wäre es verschwenderisch, die Methode mit bestimmten Parametern kontinuierlich nachzuschlagen und sie dann jedes Mal auszuführen.

Stöbern Sie in der Quelle und schauen Sie sich an, was getan wird.

mP.
quelle
3

Wie bei allem geht es darum, die Situation einzuschätzen. In DotNetNuke gibt es eine ziemlich zentrale Komponente namens FillObject, die Reflexion verwendet, um Objekte aus Datenzeilen zu füllen.

Dies ist ein recht häufiges Szenario, und es gibt einen Artikel über MSDN, Verwenden der Reflexion zum Binden von Geschäftsobjekten an ASP.NET-Formularsteuerelemente , der die Leistungsprobleme behandelt.

Abgesehen von der Leistung ist eine Sache, die ich an der Verwendung von Reflection in diesem bestimmten Szenario nicht mag, dass sie dazu neigt, die Fähigkeit zu verringern, den Code auf einen Blick zu verstehen, was für mich die Mühe nicht wert zu sein scheint, wenn man bedenkt, dass man auch die Kompilierung verliert Zeitsicherheit im Gegensatz zu stark typisierten Datasets oder ähnlichem wie LINQ to SQL .

Lomaxx
quelle
2

Reflexion verlangsamt die Leistung Ihrer App nicht drastisch. Möglicherweise können Sie bestimmte Dinge schneller erledigen, indem Sie keine Reflexion verwenden. Wenn jedoch Reflexion der einfachste Weg ist, um bestimmte Funktionen zu erreichen, verwenden Sie sie. Sie können Ihren Code jederzeit außerhalb von Reflection umgestalten, wenn dies zu einem Perf-Problem wird.

Chris Pietschmann
quelle
1

Ich denke, Sie werden feststellen, dass die Antwort lautet, es kommt darauf an. Es ist keine große Sache, wenn Sie es in Ihre Aufgabenlistenanwendung aufnehmen möchten. Es ist eine große Sache, wenn Sie es in die Persistenzbibliothek von Facebook aufnehmen möchten.

Tsimon
quelle