2009-07-22 7 views

Antwort

2

Die Reflektion funktioniert gut, nur ist viel mehr als statischer Code.

Sagen Sie bitte diesen Code-Schnipsel haben:

typeof(SomeClass).GetMethod("SomeStaticMethod"). 
Invoke(null, new object[] { 1, 2, 3 }); 

Dies ist die gleiche wie folgt aus:

SomeClass.SomeStaticMethod(1, 2, 3); 

Aber es sollte klar sein, dass die erste viel mehr Arbeit zu tun hat. Es muss Typinformationen erhalten, es durchlaufen, um zu sehen, ob es eine SomeStaticMethod-Methode gibt, welche Art von Methode es ist, die Methode für eine Instanz aufrufen oder nicht, wenn es statisch ist und das Objektarray übergibt Parameter, Boxen/Unboxing die ganzen Zahlen auch in diesem Fall.

Und dies ist wahrscheinlich eine sehr breite Zusammenfassung, es gibt keinen Zweifel mehr noch. Dennoch ist die Reflektion immer noch sehr schnell und wird in vielen Bereichen verwendet, von der Datenbindung in WinForms bis zum Modellieren der Bindung in ASP.NET MVC (jede Anfrage, die Sie auf dieser Site machen, die auf MVC basiert, beinhaltet eine ganze Reihe von Überlegungen und dennoch ist die Site sehr schnell und MVC wird als ein sehr schnelles Framework angesehen).

1

Da es zur Laufzeit Zeichenfolgen-Lookups (von Typ- und Elementnamen) sowie zusätzliche Boxing/Unboxing für Werttypen umfasst.

4

Hervorragender Artikel darüber auf MSDN: Dodge Common Performance Pitfalls to Craft Speedy Applications. Grundsätzlich ist es eine Frage der späten und frühen Bindung. Das heißt, was zur Kompilierzeit entschieden werden kann und was zur Laufzeit entschieden werden muss. Von diesem Artikel ...

Die spät gebundene Fälle sind MethodBase.Invoke, Dynamic über Invoke, Type.InvokeMember und spät gebundenen Delegierten Anrufe (Anrufe auf Delegierten über Delegate.DynamicInvoke). Alle diese Methoden kommen mit deutlich negativer Leistungsfolgen als die frühen gebundenen Fälle. Selbst im besten Fall sind sie typischerweise eine Größenordnung von Größenordnung langsamer als die langsamste früh gebundenen Fall.

Er bricht unsere ziemlich einige Leistungstests der verschiedenen Arten, frühe und spät gebundene Anrufe zu machen. Es ist das Lesen wert.

1

Bei Reflection wird zu den Metadaten gegangen, um die Namen in Token aufzulösen. Dann werden diese Token zum Suchen und Abrufen der gewünschten Daten verwendet (z. B. wird ein Methoden-Token verwendet, um Informationen über die Methode, Parameter usw. zu erhalten). .etc).

Dieser Prozess ist aus zwei Gründen teuer. 1- Eine Menge Nachschlagen läuft. 2- Berühren von Seiten, die normalerweise nicht berührt werden (kalte Seiten), die die Metadatentabellen enthalten.

Der direkte Zugriff auf Metadaten ist teuer, die CLR verwaltet Caches, um diesen Prozess schnell zu machen und die Metadatentabellen nicht zu berühren, wenn Sie nicht-reflektiv auf Dinge zugreifen. Sobald Sie jedoch zur Reflektion gehen, umgehen wir diese Caches und gehen direkt zur Quelle.

16

Reflexion führt nicht gut

, die eine sehr belastete Aussage ist. "Gute Leistung" ist relativ. Verglichen mit statischem Code führen reflektierende Aufrufe nicht ganz so gut. In fast allen Fällen ist jedoch die Reflexion in .NET extrem schnell. Ich kann das nicht genug untertreiben. Reflection erhielt einen schlechten Ruf von .NET 1.x Tagen und vielleicht anderen Sprachen, aber die Reflektion in .NET 2.0+ ist bullysingly quick.

In 99% der Fälle ist die "Reflexion zu langsam" irrelevant. Ich bezweifle, dass Sie die Leistungseinwirkung eines reflektierenden Anrufs gegenüber einer statischen Messung messen müssten.

+0

Nun, ich habe Reflexion in einer Windows Forms App verwendet, um eine dynamische Benutzeroberfläche zu erstellen, und ich sah keine Leistungsbedenken. Natürlich kann es in einer "performant kritischen" Anwendung anders sein, weiß ich nicht. – Malcolm

0

Reflection funktioniert gut in .NET - für was es tut.

Allerdings erfordert die Reflektion, da es sich um eine Laufzeitanalyse von bereits kompilierten Typen handelt, einiges an Overhead. Im Allgemeinen wird es eine Weile dauern, Dinge wie das Suchen von Strings nach statischen Informationen und das Durchlaufen der Klassenmetadaten usw. zu erledigen.

Das ist nicht zu sagen, dass es wirklich langsam ist - es ist nur viel langsamer als vollständig kompiliert, Strait Methodenaufrufe und Nachschlagewerke. Es sollte - aber ich denke wirklich daran mehr als kompilierter Code ist schneller als dynamisch nachschlagen Informationen in jedem System.

5

Einfach zu sagen, dass "Reflection" langsam ist, ist verdammt viel Funktionalität unter einer sehr breiten Decke. Reflection in .NET gibt es in mehreren Klassen mit jeweils unterschiedlicher "Performance". Zum einen ist die Verwendung des Operators typeof() eigentlich eine Form der Reflektion ... Er fragt die CLR-Metadaten nach einem Typ ab. typeof() führt jedoch extrem schnell aus (in nahezu freier Zeit). Die Verwendung anderer typbezogener "Reflektionen", wie der is-Operator, sizeof()-Operator usw., ist ebenfalls nahezu frei (sie verhalten sich grundsätzlich so, als wären sie statischer Code).)

Reflection verwendet, um Informationen über einen Typ abzurufen, während langsamer als typeof(), ist auch sehr, sehr schnell in Anbetracht der Menge an Zeiger Traversal und Metadaten Sondierung, die weitergeht. Metadata Probing ist eine ziemlich übliche Methode mit .NET-Code, insbesondere wenn es um die Arbeit mit benutzerdefinierten Attributen geht.

Die große Leistungsbeeinträchtigung in Bezug auf Reflexion hat mit dem Aufruf zu tun. Der Zugriff auf Typinformationen und das Lesen von Metadaten ist ziemlich leicht. In dem Moment, in dem Sie den dynamischen Aufruf von Eigenschaften, Indexern oder Methoden verwenden oder dynamisch neue Typen durch Reflektion konstruieren, nehmen Sie eine Leistungssteigerung in Größenordnungen vor.

Reflection ist immer noch eine In-Process-Ausführung. Bevor Sie sich jedoch Gedanken über den Leistungseinbruch eines kleinen dynamischen Aufrufs machen, sollten Sie sicherstellen, dass es keine wesentlich größeren Leistungsengpässe wie Interprozessausführung oder Netzwerk gibt Anrufe (z. B. Datenbank, Webservice usw.) Wenn es um die Leistung geht, beginnen Sie mit dem größten Leistungseinbruch und arbeiten Sie sich von dort aus nach unten. Reflektion, einschließlich dynamischen Aufrufs, ist normalerweise eines der letzten Dinge, die Sie aus Performance-Sicht beachten sollten.

Nachtrag:

Ein bisschen eines nach Gedanken, aber wenn Sie ein hohes Maß an dynamischem Aufruf spät gebundenen Typ Mitglieder benötigen, Sie in leichte Codegenerierung aussehen sollten. Mithilfe des System.Reflection.Emit-Namespace können Sie Dienstprogramme wie DynamicMethod verwenden, um während der Laufzeit Lightweight-Code zu generieren, der früh gebundene Aufrufe ausführen kann. Durch die Zwischenspeicherung dieses generierten Codes werden die anfänglichen Kosten für die Generierung reduziert, sodass Sie die Vorteile von spät gebundenen Anrufen mit früh gebundener Leistung nutzen können.

Verwandte Themen