Quelle est la lenteur de la reflection

J’ai récemment créé une couche d’interface pour distinguer le DataAccessProvider de notre couche de logique métier. Avec cette approche, nous pouvons changer notre choix de DataAccessProvider quand nous le souhaitons en modifiant les valeurs dans Web / App.Config. (Plus de détails peuvent être donnés si nécessaire).

Quoi qu’il en soit, pour ce faire, nous utilisons la reflection pour accomplir notre classe DataProvider sur laquelle nous pouvons travailler.

///  /// The constructor will create a new provider with the use of reflection. /// If the assembly could not be loaded an AssemblyNotFoundException will be thrown. ///  public DataAccessProviderFactory() { ssortingng providerName = ConfigurationManager.AppSettings["DataProvider"]; ssortingng providerFactoryName = ConfigurationManager.AppSettings["DataProviderFactory"]; try { activeProvider = Assembly.Load(providerName); activeDataProviderFactory = (IDataProviderFactory)activeProvider.CreateInstance(providerFactoryName); } catch { throw new AssemblyNotFoundException(); } } 

Mais maintenant je me demande à quel point la reflection est lente?

    Dans la plupart des cas: plus que rapide. Par exemple, si vous l’utilisez pour créer un object wrapper DAL, le temps nécessaire à la création de l’object par reflection sera minuscule par rapport au temps nécessaire pour se connecter à un réseau. Donc, l’optimisation serait une perte de temps.

    Si vous utilisez la reflection dans une boucle serrée, il existe des astuces pour l’améliorer:

    • génériques (en utilisant un wrapper where T : new() et MakeGenericType )
    • Delegate.CreateDelegate (à un délégué typé; ne fonctionne pas pour les constructeurs)
    • Reflection.Emit – hardcore
    • Expression (comme Delegate.CreateDelegate , mais plus flexible et fonctionne pour les constructeurs)

    Mais pour vos besoins, CreateInstance convient parfaitement. S’en tenir à cela, et garder les choses simples.


    Edit: alors que le point sur la performance relative rest, et que la chose la plus importante, “mesurez-le”, rest, je devrais clarifier une partie de ce qui précède. Parfois … ça compte. Mesurer en premier. Cependant, si vous trouvez que c’est trop lent, vous voudrez peut-être regarder quelque chose comme FastMember , qui fait tout le code de Reflection.Emit discrètement en arrière-plan, pour vous donner une API facile à utiliser. par exemple:

     var accessor = TypeAccessor.Create(type); List results = new List(); foreach(var row in rows) { object obj = accessor.CreateNew(); foreach(var col in cols) { accessor[obj, col.Name] = col.Value; } results.Add(obj); } 

    ce qui est simple, mais sera très rapide. Dans l’exemple spécifique que je mentionne à propos d’un wrapper DAL – si vous faites cela beaucoup, considérez quelque chose comme dapper , qui fait à nouveau tout le code Reflection.Emit en arrière-plan pour vous offrir l’API la plus rapide mais facile à utiliser:

     int id = 12345; var orders = connection.Query( "select top 10 * from Orders where CustomerId = @id order by Id desc", new { id }).ToList(); 

    C’est plus lent que le code non réfléchissant. L’important n’est pas si c’est lent, mais si c’est lent là où ça compte . Par exemple, si vous instanciez des objects en utilisant la reflection dans un environnement Web où la concordance attendue peut atteindre 10 Ko, cela sera lent.

    Quoi qu’il en soit, il est bon de ne pas s’inquiéter de la performance à l’avance. Si les choses se révèlent lentes, vous pouvez toujours les accélérer si vous avez conçu les choses correctement afin que les pièces que vous attendiez puissent être optimisées à l’avenir soient localisées.

    Vous pouvez vérifier cet article si vous avez besoin d’accélérer:

    Dynamique … mais rapide: le conte des trois singes, un loup et les classes DynamicMethod et ILGenerator

    Voici quelques liens qui pourraient vous aider:

    • Ce gars a fait des tests et fournit quelques mésortingques
    • Article MSDN “Pièges courants de performance Dodge pour concevoir des applications rapides”

    La reflection n’est pas si lente. Invoquer une méthode par reflection est environ 3 fois plus lent que la méthode normale. Cela ne pose aucun problème si vous le faites une seule fois ou dans des situations non critiques. Si vous l’utilisez 10 000 fois dans une méthode critique, je souhaiterais modifier l’implémentation.

    En plus de suivre les liens donnés dans d’autres réponses et de vous assurer que vous n’écrivez pas de code “pathalogiquement mauvais”, pour moi, la meilleure réponse est de le tester vous-même.

    Vous seul savez où sont vos goulots, combien de fois votre code de reflection sera utilisé, si le code de reflection sera dans des boucles serrées, etc. Vous connaissez votre parsing de rentabilité, combien d’utilisateurs accèderont à votre site, quelles sont les exigences de perf.

    Cependant, étant donné le fragment de code que vous avez montré ici, je suppose que la surcharge de reflection ne sera pas un problème majeur.

    Les fonctionnalités de test Web et de test de performance de VS.NET devraient faciliter la mesure des performances de ce code.

    Si vous n’utilisez pas la reflection, à quoi ressemblera votre code? Quelles limitations aura-t-il? Il se peut que vous ne puissiez pas vivre avec les limitations que vous rencontrez si vous supprimez le code de reflection. Il pourrait être intéressant d’essayer de concevoir ce code sans la reflection pour voir si c’est possible ou si l’alternative est souhaitable.

    J’ai pensé faire un test rapide pour démontrer à quel point la reflection est comparée à sans.

    Avec reflection

    • Instanciation de 58 objects en parcourant chacun de leurs atsortingbuts et leur correspondance
    • Durée totale: 52254 nanosecondes

       while (reader.Read()) { ssortingng[] columns = reader.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry(); IEnumerable rawPayFileAtsortingbutes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Atsortingbute.IsDefined(prop, typeof(CustomIndexAtsortingbute))); foreach (var property in rawPayFileAtsortingbutes) { int propertyIndex = ((CustomIndexAtsortingbute)property.GetCustomAtsortingbute(typeof(CustomIndexAtsortingbute))).Index; if (propertyIndex < columns.Length) property.SetValue(toReturn, columns[propertyIndex]); else break; } } 

    Sans reflection

    • Instancier 58 objects en créant un nouvel object
    • Temps total: 868 nanosecondes

        while (reader2.Read()) { ssortingng[] columns = reader2.CurrentRecord; CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() { ColumnZero = columns[0], ColumnOne = columns[1], ColumnTwo = columns[2], ColumnThree = columns[3], ColumnFour = columns[4], ColumnFive = columns[5], ColumnSix = columns[6], ColumnSeven = columns[7], ColumnEight = columns[8], ColumnNine = columns[9], ColumnTen = columns[10], ColumnEleven = columns[11], ColumnTwelve = columns[12], ColumnThirteen = columns[13], ColumnFourteen = columns[14], ColumnFifteen = columns[15], ColumnSixteen = columns[16], ColumnSeventeen = columns[17] }; } 

    Bien que ce ne soit pas tout à fait juste car la reflection doit également récupérer un atsortingbut spécifique de chaque propriété 58 * 18 fois en plus de créer un nouvel object par reflection, mais au moins cela fournit une certaine perspective.

    Je faisais quelque chose de similaire jusqu’à ce que je commence à jouer avec IoC. J’utiliserais une définition d’object Spring pour spécifier le fournisseur de données – SQL, XML ou Mocks!