Quanto costa .NET reflection?


210

Sento costantemente quanto sia brutta la riflessione. Mentre generalmente evito la riflessione e raramente trovo situazioni in cui è impossibile risolvere il mio problema senza di esso, mi chiedevo ...

Per coloro che hanno usato la riflessione nelle applicazioni, hai misurato i risultati delle prestazioni ed è davvero così male?


Potresti anche voler dare un'occhiata a questa domanda. stackoverflow.com/questions/224232/...
smaclell

1
Usa l'API su fastflect.codeplex.com. Accelererà la riflessione di circa 500x per getter / setter / invocatori e altre cose. Anche la fonte e le informazioni su come funziona sono necessarie per estenderla.
Brandon Moore,

3
Come vengono verificate queste informazioni nel 2014? Qualcosa è cambiato in questi 4 anni?
Arnthor,

1
Il semplice compito di assegnare un valore a una proprietà dell'istanza è circa 150 volte più lento nel farlo con la riflessione (PropertyInfo.SetValue (istanza, valore)) rispetto alla codifica semplice (istanza.property = valore). Questo è in .NET 4.0
Thanasis Ioannidis

Risposte:


130

È. Ma dipende da cosa stai cercando di fare.

Uso il reflection per caricare in modo dinamico assembly (plug-in) e la sua "penalità" di prestazioni non è un problema, poiché l'operazione è qualcosa che faccio durante l'avvio dell'applicazione.

Tuttavia, se stai riflettendo all'interno di una serie di loop nidificati con chiamate di riflessione su ciascuno, direi che dovresti rivisitare il tuo codice :)

Per operazioni "un paio di volte", la riflessione è perfettamente accettabile e non noterai alcun ritardo o problema. È un meccanismo molto potente ed è persino usato da .NET, quindi non vedo perché non dovresti provarlo.


Ho usato la riflessione per ottenere il metodo, il nome della classe del metodo corrente per registrare l'errore in try-catch. sostanzialmente per evitare di codificare il nome della funzione durante la registrazione dell'errore. Mi devo preoccupare?
Sangram Nandkhile,

@Sangram no, va bene
Karthik AMR,

@Sangram no, a meno che tu non stia riscontrando molti errori che richiedono costantemente la cattura, che quindi dovrebbe essere un problema diverso :)
Martin Marconcini

5
@Sangram mentre le prestazioni di riflessione non dovrebbero essere il problema nel tuo caso, sembra che tu stia cercando di reimplementare ciò che le semplici vecchie eccezioni forniscono in un modo molto più elegante fuori dagli schemi ...
Jacek Gorgoń,

152

Nel suo discorso The Performance of Everyday Things , Jeff Richter mostra che chiamare un metodo per riflessione è circa 1000 volte più lento di chiamarlo normalmente.

Il consiglio di Jeff: se è necessario chiamare il metodo più volte, utilizzare reflection una volta per trovarlo, quindi assegnarlo a un delegato , quindi chiamare il delegato.


18
Ho partecipato anche a Devscovery e concordo con questi risultati per .NET 3.5. La ricompilazione del programma di benchmark delle prestazioni Devscovery per .NET 4 mostra un enorme miglioramento! Il costo scende fino a 100 volte più lentamente. L'uso della riflessione per le ricerche di typeof () è invariato tra .NET 3.5 e .NET 4.
John Wigger,

61

Le prestazioni di riflessione dipenderanno dall'implementazione (le chiamate ripetitive devono essere memorizzate nella cache, ad esempio:) entity.GetType().GetProperty("PropName"). Poiché la maggior parte della riflessione che vedo quotidianamente viene utilizzata per popolare entità da lettori di dati o altre strutture di tipo repository, ho deciso di confrontare le prestazioni in modo specifico sulla riflessione quando viene utilizzato per ottenere o impostare le proprietà di un oggetto.

Ho escogitato un test che ritengo corretto poiché memorizza tutte le chiamate ripetute nella cache e solo volte la chiamata SetValue o GetValue effettiva. Tutto il codice sorgente per il test delle prestazioni è in bitbucket all'indirizzo: https://bitbucket.org/grenade/accessortest . Il controllo è benvenuto e incoraggiato.

La conclusione a cui sono giunto è che non è pratico e non fornisce notevoli miglioramenti delle prestazioni per rimuovere la riflessione in un livello di accesso ai dati che restituisce meno di 100.000 righe in un momento in cui l'implementazione della riflessione viene eseguita correttamente.

Grafico del tempo (y) rispetto al numero di entità popolate (x)

Il grafico sopra mostra l'output del mio piccolo benchmark e mostra che i meccanismi che superano la riflessione, lo fanno solo dopo il segno dei 100.000 cicli. La maggior parte dei DAL restituisce solo diverse centinaia o forse migliaia di righe alla volta e a questi livelli la riflessione funziona bene.


9
Non necessariamente. Le tue conversioni DAL possono riguardare solo alcune migliaia di elementi, ma moltiplicalo per gli utenti simultanei che utilizzano la tua applicazione (se è web) e potrebbe sommarsi come se dovessi convertire milioni di elementi. Se un metodo particolare è 100 volte più lento, sarà molto più lento su set piccoli e grandi. Più lento è più lento.
Robert Koritnik,

@RobertKoritnik Questo presuppone che i metodi web sul tuo server non siano asincroni
Kurren,

L'asincronicità di @kurren non influisce sulla riflessione ma piuttosto sulle risorse del server. I metodi Web asincroni saranno ovviamente in grado di servire più utenti, ma la riflessione sarà ancora lenta. E la riflessione di per sé AFAIK è comunque un processo sincrono. Il recupero dei dati d'altra parte sarà l'unica parte che giocherà bene con il design asincrono.
Robert Koritnik,

3
Qual è il metodo Hyper sul grafico? In che cosa differisce da Reflector?
Bryan Legend,



12

La mia esperienza più pertinente è stata la scrittura di codice per confrontare due entità dati dello stesso tipo in un modello di oggetti di grandi dimensioni dal punto di vista delle proprietà. Ha funzionato, provato, corso come un cane, ovviamente.

Ero scoraggiato, poi durante la notte mi sono reso conto che senza cambiare la logica, avrei potuto usare lo stesso algoritmo per generare automaticamente metodi per fare il confronto ma accedere staticamente alle proprietà. Non ci è voluto molto tempo per adattare il codice a questo scopo e ho avuto la possibilità di fare un confronto approfondito dal punto di vista delle proprietà con entità con codice statico che poteva essere aggiornato con un clic di un pulsante ogni volta che il modello a oggetti cambiava.

Il mio punto è: nelle conversazioni con i colleghi, poiché ho più volte sottolineato che il loro uso della riflessione potrebbe essere di generare automaticamente il codice per la compilazione piuttosto che eseguire operazioni di runtime e questo vale spesso la pena considerare.


Considerando che Visual Studio ha un supporto modello così eccellente, è un modo pratico di usare la generazione del codice
Sebastian

12

Non in modo massiccio. Non ho mai avuto problemi con lo sviluppo del desktop a meno che, come afferma Martin, non lo utilizzi in una posizione sciocca. Ho sentito molte persone avere paure assolutamente irrazionali per le sue prestazioni nello sviluppo desktop.

Nel Compact Framework (in cui mi trovo di solito), tuttavia, è praticamente un anatema e dovrebbe essere evitato come la peste nella maggior parte dei casi. Posso ancora cavarmela usando di rado, ma devo stare molto attento con la sua applicazione che è molto meno divertente. :(


5
+1 per avermi insegnato una nuova parola: anatema. Anche per menzione di paure irrazionali. Temo che i programmatori che temono irrazionalmente - dimostrano che non sanno davvero cosa stanno facendo e basano semplicemente quello che fanno su ciò che gli altri dicono. tosse carico di culto tosse
bsneeze

1
Ahhhh Cargo Cult. Ora c'è un bell'esempio di curioso comportamento umano.
Quibblesome

10

È abbastanza grave che devi preoccuparti anche della riflessione fatta internamente dalle librerie .NET per il codice critico per le prestazioni.

L'esempio seguente è obsoleto - vero al momento (2008), ma molto tempo fa è stato risolto nelle versioni CLR più recenti. Tuttavia, la riflessione in generale è ancora un po 'costosa!

Caso in questione: non utilizzare mai un membro dichiarato come "Oggetto" in un'istruzione lock (C #) / SyncLock (VB.NET) nel codice ad alte prestazioni. Perché? Poiché il CLR non è in grado di bloccare un tipo di valore, ciò significa che deve eseguire un tipo di riflesso di runtime per verificare se l'oggetto è effettivamente un tipo di valore anziché un tipo di riferimento.


13
per essere onesti, un controllo del tipo di riflessione è veloce.
Jimmy,

1
Per tale "codice critico per le prestazioni" dovresti davvero utilizzare .NET per cominciare?
Seph

1
@Seph: porzioni dinamiche / di riflessione di .NET, n. Ma al solito C # /. NET, perché no? Le accelerazioni C ++ vs C # sono marginali a livello di applicazione (C ++ è ancora più veloce di qualche% nelle routine matematiche intensive). E suppongo che non stai suggerendo il montaggio ...
DeepSpace101

Un tipo di valore inscatolato (es. Oggetto) può essere bloccato. @BryceWagner è corretto.
Uccellino

1
Per essere onesti (per me), è più preciso dire che la risposta è "obsoleta", piuttosto che "semplice assurdità". Le mie osservazioni sul comportamento di lock (obj) erano accurate al momento in cui sono state scritte, ma quel comportamento specifico per l'implementazione del CLR è scomparso da tempo.
McKenzieG1,

5

Come per tutto ciò che riguarda la programmazione, è necessario bilanciare i costi delle prestazioni con qualsiasi vantaggio ottenuto. La riflessione è uno strumento prezioso se usato con cura. Ho creato una libreria di mappatura O / R in C # che ha usato la riflessione per eseguire i collegamenti. Questo ha funzionato in modo fantastico. La maggior parte del codice di riflessione è stata eseguita una sola volta, quindi qualsiasi hit delle prestazioni è stato piuttosto ridotto, ma i vantaggi sono stati notevoli. Se stessi scrivendo un nuovo algoritmo di ordinamento confuso, probabilmente non utilizzerei la riflessione, poiché probabilmente ridimensionerebbe male.

Apprezzo che non ho risposto esattamente alla tua domanda qui. Il mio punto è che non importa davvero. Usa la riflessione dove appropriato. È solo un'altra caratteristica della lingua che devi imparare come e quando usare.


3

La riflessione può avere un notevole impatto sulle prestazioni se la si utilizza per la creazione frequente di oggetti. Ho sviluppato un'applicazione basata sul Blocco applicazione dell'interfaccia utente composita che si basa fortemente sulla riflessione. Si è verificato un notevole deterioramento delle prestazioni correlato alla creazione di oggetti tramite la riflessione.

Tuttavia, nella maggior parte dei casi non ci sono problemi con l'utilizzo della riflessione. Se la tua unica necessità è di ispezionare un po 'di assemblaggio, consiglierei Mono.Cecil che è molto leggero e veloce


3

La riflessione è costosa a causa dei numerosi controlli che il runtime deve eseguire ogni volta che si effettua una richiesta per un metodo che corrisponde a un elenco di parametri. Da qualche parte nel profondo, esiste un codice che scorre su tutti i metodi per un tipo, verifica la sua visibilità, controlla il tipo restituito e controlla anche il tipo di ogni singolo parametro. Tutta questa roba costa tempo.

Quando esegui quel metodo internamente c'è del codice che fa cose come il controllo, hai passato un elenco compatibile di parametri prima di eseguire il metodo di destinazione effettivo.

Se possibile, si consiglia sempre di memorizzare nella cache l'handle del metodo se si intende riutilizzarlo continuamente in futuro. Come tutti i buoni consigli di programmazione, spesso ha senso evitare di ripetersi. In questo caso sarebbe inutile cercare continuamente il metodo con determinati parametri e quindi eseguirlo ogni volta.

Dai un'occhiata alla fonte e dai un'occhiata a cosa si sta facendo.


3

Come per tutto, si tratta di valutare la situazione. In DotNetNuke c'è un componente abbastanza core chiamatoFillObject che usa la riflessione per popolare gli oggetti dai datarows.

Questo è uno scenario abbastanza comune e c'è un articolo su MSDN, Utilizzo di Reflection per associare gli oggetti business ai controlli modulo ASP.NET che copre i problemi di prestazioni.

Prestazioni a parte, una cosa che non mi piace usare la riflessione in quel particolare scenario è che tende a ridurre la capacità di comprendere il codice a colpo d'occhio che per me non sembra valere la pena se consideri che perdi anche la compilazione sicurezza temporale rispetto a set di dati fortemente tipizzati o qualcosa come LINQ to SQL .


2

Reflection non rallenta drasticamente le prestazioni della tua app. Potresti essere in grado di fare alcune cose più velocemente non usando la riflessione, ma se Reflection è il modo più semplice per ottenere alcune funzionalità, allora usalo. Puoi sempre rifattorizzare il codice lontano da Reflection se diventa un problema perfetto.


1

Penso che scoprirai che la risposta è, dipende. Non è un grosso problema se si desidera inserirlo nell'applicazione dell'elenco attività. È un grosso problema se vuoi metterlo nella libreria di persistenza di Facebook.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.