Combien coûte la réflexion .NET?

210

J'entends constamment à quel point la réflexion est mauvaise à utiliser. Bien que j'évite généralement la réflexion et que je trouve rarement des situations où il est impossible de résoudre mon problème sans cela, je me demandais ...

Pour ceux qui ont utilisé la réflexion dans les applications, avez-vous mesuré les performances et est-ce vraiment si mauvais?

Dan Herbert
la source
Vous pouvez également consulter cette question. stackoverflow.com/questions/224232/…
smaclell
1
Utilisez l'API à Fastflect.codeplex.com. Cela accélérera la réflexion de 500x pour les getters / setters / invokers et d'autres trucs. La source et les informations sur son fonctionnement sont également disponibles si vous avez besoin de les étendre.
Brandon Moore
3
Comment ces informations sont-elles vérifiées en 2014? Quelque chose a changé au cours de ces 4 années?
Arnthor
1
La tâche simple d'attribuer une valeur à une propriété d'instance est environ 150 fois plus lente à le faire avec la réflexion (PropertyInfo.SetValue (instance, valeur)) qu'avec un codage simple (instance.property = valeur) .C'est dans .NET 4.0
Thanasis Ioannidis

Réponses:

130

C'est. Mais cela dépend de ce que vous essayez de faire.

J'utilise la réflexion pour charger dynamiquement des assemblages (plugins) et sa "pénalité" de performance n'est pas un problème, car l'opération est quelque chose que je fais lors du démarrage de l'application.

Cependant, si vous réfléchissez à l'intérieur d'une série de boucles imbriquées avec des appels de réflexion sur chacune, je dirais que vous devriez revoir votre code :)

Pour les opérations "quelques fois", la réflexion est parfaitement acceptable et vous ne remarquerez aucun retard ou problème. C'est un mécanisme très puissant et il est même utilisé par .NET, donc je ne vois pas pourquoi vous ne devriez pas l'essayer.

Martin Marconcini
la source
J'ai utilisé la réflexion pour obtenir la méthode, le nom de classe de la méthode actuelle pour enregistrer l'erreur dans try-catch. essentiellement pour éviter de coder en dur le nom de la fonction lors de l'enregistrement de l'erreur. Dois-je m'inquiéter?
Sangram Nandkhile
@Sangram non, ça va
Karthik AMR
@Sangram non, sauf si vous rencontrez beaucoup d'erreurs qui nécessitent une capture constante, ce qui devrait alors être un problème différent :)
Martin Marconcini
5
@Sangram alors que la performance de réflexion ne devrait pas être le problème dans votre cas, il semble que vous essayez de réimplémenter les anciennes exceptions de manière beaucoup plus élégante ...
Jacek Gorgoń
152

Dans son exposé The Performance of Everyday Things , Jeff Richter montre qu'appeler une méthode par réflexion est environ 1000 fois plus lent que l'appeler normalement.

Conseil de Jeff: si vous devez appeler la méthode plusieurs fois, utilisez la réflexion une fois pour la trouver, puis affectez-la à un délégué , puis appelez le délégué.

ESRogs
la source
18
J'ai également assisté à Devscovery et je suis d'accord avec ces résultats pour .NET 3.5. La recompilation du programme de référence de performances Devscovery pour .NET 4 montre une amélioration massive! Le coût descend jusqu'à 100 fois plus lentement. L'utilisation de la réflexion pour les recherches typeof () est inchangée entre .NET 3.5 et .NET 4.
John Wigger
61

Les performances de réflexion dépendront de l'implémentation (les appels répétitifs doivent être mis en cache, par exemple:) entity.GetType().GetProperty("PropName"). Étant donné que la plupart des réflexions que je vois quotidiennement sont utilisées pour remplir des entités à partir de lecteurs de données ou d'autres structures de type référentiel, j'ai décidé de comparer les performances spécifiquement à la réflexion lorsqu'elle est utilisée pour obtenir ou définir les propriétés d'un objet.

J'ai conçu un test qui je pense est juste car il met en cache tous les appels répétés et uniquement les appels SetValue ou GetValue réels. Tout le code source du test de performance se trouve dans bitbucket à l' adresse : https://bitbucket.org/grenade/accessortest . L'examen est le bienvenu et encouragé.

La conclusion à laquelle je suis arrivé est qu'il n'est pas pratique et n'apporte pas d'améliorations notables des performances pour supprimer la réflexion dans une couche d'accès aux données qui renvoie moins de 100 000 lignes à la fois lorsque l'implémentation de la réflexion est bien effectuée.

Graphique du temps (y) par rapport au nombre d'entités peuplées (x)

Le graphique ci-dessus montre la sortie de mon petit repère et montre que les mécanismes qui surpassent la réflexion ne le font sensiblement qu'après la barre des 100 000 cycles. La plupart des DAL ne renvoient que plusieurs centaines ou peut-être des milliers de lignes à la fois et à ces niveaux, la réflexion fonctionne très bien.

grenade
la source
9
Pas nécessairement. Vos conversions DAL peuvent ne concerner que quelques milliers d'éléments, mais multipliez-les par des utilisateurs simultanés utilisant votre application (si c'est Web) et cela peut s'additionner comme si vous convertissiez des millions d'éléments. Si une méthode particulière est 100 fois plus lente, elle sera beaucoup plus lente sur les petits et les grands ensembles. Plus lent est plus lent.
Robert Koritnik
@RobertKoritnik Cela suppose que les méthodes Web sur votre serveur ne sont pas asynchrones
Kurren
@kurren asynchronicity n'a pas d'impact sur la réflexion mais plutôt sur les ressources du serveur. Les méthodes Web asynchrones pourront bien sûr servir plus d'utilisateurs, mais la réflexion sera encore lente. Et la réflexion en soi AFAIK est de toute façon un processus synchrone. La récupération de données, d'autre part, sera la seule partie qui jouera bien avec la conception asynchrone.
Robert Koritnik
3
Quelle est la méthode Hyper sur le graphique? En quoi est-ce différent de Reflector?
Bryan Legend
J'aurais référencé ce @LoneCoder: codeproject.com/Articles/18450/... par stackoverflow.com/users/23354/marc-gravell
grenade
14

Si vous n'êtes pas dans une boucle, ne vous en faites pas.

David Plumpton
la source
12

Mon expérience la plus pertinente a été d'écrire du code pour comparer deux entités de données du même type dans un grand modèle d'objet en termes de propriété. Je l'ai fait fonctionner, je l'ai essayé, j'ai couru comme un chien, évidemment.

J'étais découragé, puis j'ai réalisé du jour au lendemain que sans changer la logique, je pouvais utiliser le même algorithme pour générer automatiquement des méthodes pour faire la comparaison mais accéder statiquement aux propriétés. Il n'a fallu aucun temps pour adapter le code à cette fin et j'ai eu la possibilité de faire une comparaison approfondie des entités avec du code statique qui pouvait être mis à jour en un clic sur un bouton chaque fois que le modèle d'objet changeait.

Mon point étant: dans les conversations avec des collègues depuis que j'ai plusieurs fois souligné que leur utilisation de la réflexion pourrait être de générer automatiquement du code pour compiler plutôt que d'effectuer des opérations d'exécution et cela vaut souvent la peine d'être considéré.

Gaz
la source
Étant donné que Visual Studio a un excellent support de modèle, c'est un moyen pratique d'utiliser la génération de code
Sebastian
12

Pas massivement. Je n'ai jamais eu de problème avec cela dans le développement de bureau, sauf si, comme le déclare Martin, vous l'utilisez dans un endroit idiot. J'ai entendu que beaucoup de gens ont des craintes totalement irrationnelles concernant ses performances dans le développement de postes de travail.

Dans le Compact Framework (dans lequel je suis habituellement), c'est à peu près un anathème et devrait être évité comme la peste dans la plupart des cas. Je peux toujours m'en tirer rarement, mais je dois être très prudent avec son application, ce qui est beaucoup moins amusant. :(

Quibblesome
la source
5
+1 pour m'avoir appris un nouveau mot: anathème. Aussi pour mentionner les peurs irrationnelles. J'ai peur des programmeurs qui ont peur de façon irrationnelle - cela montre qu'ils ne savent pas vraiment ce qu'ils font et fondent simplement ce qu'ils font sur ce que les autres leur disent. toux cargo toux culte
bsneeze
1
Ahhhh Cargo Cult. Il existe maintenant un bel exemple de comportement humain curieux.
Quibblesome
10

C'est déjà assez grave que vous devez vous inquiéter même de la réflexion effectuée en interne par les bibliothèques .NET pour le code critique pour les performances.

L'exemple suivant est obsolète - vrai à l'époque (2008), mais il y a longtemps corrigé dans des versions CLR plus récentes. La réflexion en général reste cependant quelque peu coûteuse!

Exemple: vous ne devez jamais utiliser un membre déclaré comme «objet» dans une instruction lock (C #) / SyncLock (VB.NET) dans du code hautes performances. Pourquoi? Parce que le CLR ne peut pas verrouiller sur un type de valeur, ce qui signifie qu'il doit effectuer une vérification du type de réflexion au moment de l'exécution pour voir si votre objet est réellement un type de valeur au lieu d'un type de référence.

McKenzieG1
la source
13
pour être juste, une vérification du type de réflexion est rapide.
Jimmy
1
Pour un tel «code critique de performance», devriez-vous vraiment utiliser .NET pour commencer?
Seph
1
@Seph: portions dynamiques / réflexion de .NET, non. Mais d'habitude C # /. NET, pourquoi pas? Les accélérations C ++ vs C # sont marginales au niveau de la couche application (C ++ est encore quelques% plus rapide sur les routines mathématiques intensives). Et je suppose que vous ne proposez pas d'assemblage ...
DeepSpace101
Un type de valeur encadré (c'est-à-dire un objet) peut être verrouillé. @BryceWagner a raison.
Fowl
1
Pour être juste (pour moi), il est plus exact de dire que la réponse est "obsolète", plutôt que "un non-sens". Mes remarques sur le comportement du verrou (obj) étaient exactes au moment où elles ont été écrites, mais ce comportement spécifique à l'implémentation du CLR a disparu depuis longtemps.
McKenzieG1
5

Comme pour tout ce qui concerne la programmation, vous devez équilibrer le coût des performances avec tout avantage obtenu. La réflexion est un outil inestimable lorsqu'elle est utilisée avec soin. J'ai créé une bibliothèque de mappage O / R en C # qui a utilisé la réflexion pour faire les liaisons. Cela a très bien fonctionné. La plupart du code de réflexion n'a été exécuté qu'une seule fois, donc tout impact sur les performances était assez faible, mais les avantages étaient énormes. Si j'écrivais un nouvel algorithme de tri fandangled, je n'utiliserais probablement pas la réflexion, car elle évoluerait probablement mal.

Je comprends que je n'ai pas exactement répondu à votre question ici. Mon point est que cela n'a pas vraiment d'importance. Utilisez la réflexion le cas échéant. C'est juste une autre fonctionnalité linguistique dont vous avez besoin pour apprendre comment et quand l'utiliser.

Mike Thompson
la source
3

La réflexion peut avoir un impact notable sur les performances si vous l'utilisez pour la création fréquente d'objets. J'ai développé une application basée sur Composite UI Application Block qui s'appuie fortement sur la réflexion. Il y avait une dégradation notable des performances liée à la création d'objets par réflexion.

Cependant, dans la plupart des cas, l'utilisation de la réflexion ne pose aucun problème. Si votre seul besoin est d'inspecter un assemblage, je recommanderais Mono.Cecil qui est très léger et rapide

aku
la source
3

La réflexion est coûteuse en raison des nombreuses vérifications que le runtime doit effectuer chaque fois que vous faites une demande pour une méthode qui correspond à une liste de paramètres. Quelque part au fond, il existe du code qui fait une boucle sur toutes les méthodes d'un type, vérifie sa visibilité, vérifie le type de retour et vérifie également le type de chaque paramètre. Tout cela coûte du temps.

Lorsque vous exécutez cette méthode en interne, il y a du code qui fait des choses comme vérifier que vous avez passé une liste de paramètres compatibles avant d'exécuter la méthode cible réelle.

Si possible, il est toujours recommandé de mettre en cache le handle de méthode si l'on veut le réutiliser continuellement à l'avenir. Comme tous les bons conseils de programmation, il est souvent judicieux d'éviter de se répéter. Dans ce cas, il serait inutile de rechercher continuellement la méthode avec certains paramètres, puis de l'exécuter à chaque fois.

Parcourez la source et regardez ce qui se fait.

mP.
la source
3

Comme pour tout, il s'agit d'évaluer la situation. Dans DotNetNuke, il existe un composant assez central appelé FillObjectqui utilise la réflexion pour remplir les objets à partir des lignes de données.

Il s'agit d'un scénario assez courant et il existe un article sur MSDN, Utilisation de la réflexion pour lier des objets métier aux contrôles de formulaire ASP.NET qui couvre les problèmes de performances.

Mis à part les performances, une chose que je n'aime pas à propos de la réflexion dans ce scénario particulier, c'est qu'elle tend à réduire la capacité de comprendre le code en un coup d'œil, ce qui ne me semble pas valoir la peine si vous considérez que vous perdez également la compilation sécurité temporelle par opposition aux ensembles de données fortement typés ou quelque chose comme LINQ to SQL .

lomaxx
la source
2

La réflexion ne ralentit pas considérablement les performances de votre application. Vous pourrez peut-être faire certaines choses plus rapidement en n'utilisant pas la réflexion, mais si la réflexion est le moyen le plus simple d'obtenir certaines fonctionnalités, utilisez-la. Vous pouvez toujours refactoriser votre code loin de Reflection si cela devient un problème de performance.

Chris Pietschmann
la source
1

Je pense que vous constaterez que la réponse est, cela dépend. Ce n'est pas grave si vous voulez le mettre dans votre application de liste de tâches. C'est un gros problème si vous voulez le mettre dans la bibliothèque de persistance de Facebook.

tsimon
la source