10
votes

Comment créer des cours de haute performance .NET à l'aide de la réflexion?

OK, nous savons donc tous que la réflexion est de plus de temps moins performant que "nouvelle" une instance de classe et, dans de nombreux cas, cela suffit, en fonction des exigences de l'application.

question: Comment pouvons-nous créer des cours de haute performance .NET à l'aide d'une stratégie de reliure tardive (réflexion).

J'ai une exigence existante qui exige des instances de classe être créées à l'aide de la réflexion (CreateInstance), mais la performance est essentielle. Dans ma situation, je crée des instances pour chaque message SMS entrant dans notre application. Pendant la production, cela pourrait facilement comporter plus d'un million par jour.

J'aimerais entendre et partager certaines idées sur la manière de créer des classes .NET sans référencer directement les classes du code, par exemple en utilisant la réflexion. Je pensais également s'il y a un moyen d'en quelque sorte cacher une usine de classe qui peut améliorer la "création" temps


8 commentaires

En attendant C # 4.0 Je suppose :)


Comment l'aide c # 4.0 serait-elle exactement?


L'utilisation de la réflexion pour créer une instance d'un objet est triviale dans 99,9% des cas. La réflexion dans .net est extrêmement rapide - écrivez-le et revenez plus tard si c'est un problème. Garantie que ce ne sera pas.


À partir de certains calculs de dos de serviette, pour le site Web principal, je travaille avec, nous avons moyen de plus sur 100 appels Activator.createInstance par seconde, toute la journée tous les jours. Non seulement ce n'est pas notre goulot d'étranglement de la performance, ce n'est même pas sur la liste des articles mesurables à améliorer potentiellement. Et c'est juste dans le code que nous avons écrit - n'incluant pas l'utilisation dans les bibliothèques que nous référons ou le framework .NET.


@Rex m; Eh bien ... j'irais aussi loin que dans de nombreux cas, il est "assez rapide" - mais cela peut souvent être beaucoup plus lent que l'approche de l'IL. Qui n'a pas d'importance si ce n'est pas un goulot d'étranglement, mais si c'était ;-p


Narc, je plaisantais comme c # 4.0 introduisant le nouveau mot clé dynamique .. (Oui, je sais que ce n'est pas vraiment ce que c'est supposé être utilisé)


Cela ressemble à une prise 22 déclaration! (: P) Réflexion et haute performance! Bonne lecture cependant.


Connexes: com / questions / 6582259 / ...


6 Réponses :


6
votes

Je ne pense pas qu'un million par jour est trop pour un simple appel de réflexion. Je crois que vous optimisez-vous, mais de toute façon, comme vous l'avez dit, créez simplement une classe d'usine à l'aide d'un seul Activator.CreateInstance Code> Appel et cache celui-ci. Les instances réelles seront créées à l'aide de l'appel de méthode CreateInstance () Code> sur l'objet renvoyé.

public interface IClassFactory {
    IClass CreateInstance();
}

public interface IClass {
   // your actual class interface.
}

public class DefaultClassFactory : IClassFactory {
    public IClass CreateInstance() {
        return new DefaultClass(); // the implementation class
    }
}


4 commentaires

Le seul HICCUP possible ici est si l'application est multithreadie, vous pouvez avoir plusieurs appels différents en utilisant le même instance et vous retrouver avec des instances avec un état mixte. Peut-être retourner un clone de l'objet si c'est un problème?


Hein? Pourquoi? L'usine créera toujours une nouvelle instance et sa sécurité-t-elle elle-même car elle n'a pas d'état interne.


@Matt il a dit une usine statique, pas la classe elle-même d'être statique. Les usines sont faciles à faire du thread-coffre-fort.


Mon mauvais, je lis cela comme établissant l'instance sous-jacente créée par l'usine en tant que statique pour un retour facile sans créer de nouvelles instances de la classe souhaitée



12
votes

1 million par jour n'est pas beaucoup; J'utiliserais simplement activator.createinstance (un test rapide à l'aide de Activator.CreatInstance (type) montre que sur mon ordinateur portable, il peut créer des objets 1M à partir d'un type in ~ 2s).

pensées sur la création d'objets rapidement:

  • Utilisez des génériques et le : nouveau () contrainte (zéro effort)
  • Utilisez dynamicmethod et écrivez l'IL (pas dure)

    Une implémentation de l'approche nouvelle (sans avoir besoin du : nouveau () contrainte externe) est affiché ici: ObjectFactory.cs . < / p>

    Pour un IIL Exemple, voir Dapper -dot-net et il.emit (opcodes.newobj, ...)


5 commentaires

@Frank: Seulement si votre constructeur n'est pas particulièrement rapide lui-même, auquel cas rien ne vous évitera. nouveau () via une contrainte générique entraîne une invocation de constructeur direct réelle, de sorte qu'il n'obtient pas plus vite que cela.


@jerry - mon chronomètre me dit sinon, désolé. Depuis le nouveau générique, je reçois toujours une performance légèrement pire (5 à 8 fois plus lent). Si vous avez un look avec ildasme, le code générique appelle activateur.CreateInstance .


@Frank - Si le temps de construction est que critique, alors dynamique serait probablement une option restante.


On dirait que le code Google a besoin du numéro de révision maintenant, alors objectfactory est à code.google.com/p/protobuf-net/source/browse/trunk/protobuf- net / ...


@Chris ah, oui; Ce fichier n'existe plus dans le coffre



5
votes

Certaines pensées:

  • Gardez une instance de chaque classe autour, une fois que vous avez trouvé besoin de cela. Puis, au lieu de CreateInstance, clonez-le.
  • Une fois que vous avez créé la première instance, conservez le type de l'instance autour. Ensuite, utilisez activator.createInstance (type)

    cache l'instance à clone ou le type dans un dictionnaire Dictionnaire ou Dictionnaire . .


1 commentaires

Clonage plus vite que de créer une instance d'un délégué mis en cache? Je ne pense pas que ce soit, alors aurait préférable de mettre en cache le contractant de la classe? Serait-ce un délégué? Si la réflexion a été utilisée pour obtenir le type, puis créer une instance, obtiendriez-vous l'entrepreneur du type ou de l'instance. Peut être ajouté à un exemple de code. Je crois comprendre que la mise en cache de la CTOR des types d'un dictionnaire serait la plus rapide.



5
votes

Comme c'est généralement le cas, Jon Skeet est votre ami ici. Voir son blog Post Faire la mouche de réflexion et explorer les délégués


0 commentaires

0
votes

Définir et mettre en place une interface au lieu d'utiliser la réflexion.


0 commentaires

1
votes

génial! L'approche de l'usine de classe semble être la voie à suivre ici.

Utilisation d'une combinaison de Assembly.createInstance (typenamestring) sur la première demande, puis cache Tapez en usine.

sur les appels suivants Activator.createInstance (type) .

Utilisation de cette approche Il est de 20% plus lent que d'utiliser un nouvel opérateur natif. Aucun gros problème là-bas!

STATS pour la création de 10 millions de Employee Objets suivants:

  • 8 secondes à l'aide de l'opérateur neuf

  • 10 secondes à l'aide de l'approche usine / type / cache.

    Voici le code d'échantillon si quelqu'un est intéressé: xxx


2 commentaires

Je pense que vous pouvez améliorer cela à l'aide d'arbres d'expression. Consultez ceci pour un Exemple < / a>.


Je ne sais pas ce que vous voyez ici en termes de libellé, comment une valeur mise en cache serait-elle 20% plus lente?