11
votes

Peut-être délégué.dynamicinvoke peut-il être évité dans ce code générique?

Cette question est en partie sur les délégués et en partie sur les génériques.

donné le code simplifié: xxx

i lue ailleurs sur SO qui invoquant un délégué directement (avec des parenthèses) est des ordres de grandeur plus rapidement que d'appeler < Code> dynamicinvoke , ce qui a du sens.

Pour l'échantillon de code ci-dessus, je me demande si je peux effectuer la vérification du type et améliorer la performance.

Certains contextes: J'ai un flux d'objets qui obtiennent de nombreux gestionnaires à divers gestionnaires, et ces gestionnaires peuvent être enregistrés / non enregistrés au moment de l'exécution. Le motif ci-dessus fonctionne parfaitement à mes fins, mais je voudrais le rendre plus snappier si possible.

une option serait de stocker action dans le dans le Dictionnaire et enveloppez le action délégués avec un autre délégué. Je n'ai pas encore comparé le changement de performance que ce deuxième appel indirect affecterait.


0 commentaires

3 Réponses :


24
votes

Je soupçonne fortement que l'enveloppement des appels serait beaucoup plus efficace que d'utiliser dynamicinvoke code>. Votre code serait alors:

internal sealed class TypeDispatchProcessor
{
    private readonly Dictionary<Type, Action<object>> _actionByType 
        = new Dictionary<Type, Action<object>>();

    public void RegisterProcedure<T>(Action<T> action)
    {
        _actionByType[typeof(T)] = item => action((T) item);
    }

    public void ProcessItem(object item)
    {
        Action<object> action;
        if (_actionByType.TryGetValue(item.GetType(), out action))
        {
            action(item);
        }
    }
}


5 commentaires

Cela peut toutefois entraîner une structure étrange et confuse.


Je doute que ce serait significativement plus confus que celui généré par un appel à Dynamicinvoke.


@Jon, merci d'avoir ajouté du poids à ma suspicion. Je vais essayer de profiler cela demain quand au bureau.


Belle solution, testée, la performance est d'env. 10 fois mieux


@Valbakhtinn, je l'ai mesuré comme approximativement 270 fois plus rapide . C'était il y a quelques années, le CLR a peut-être changé.



7
votes

Alors j'ai fait des mesures à ce sujet.

1,000,000 Action calls in 47.172 ms
1,000,000 Delegate.DynamicInvoke calls in 12,035.943 ms

1,000,000 Action calls in 44.686 ms
1,000,000 Delegate.DynamicInvoke calls in 12,318.846 ms


0 commentaires

1
votes

Si vous devez étendre ceci pour emballer des invocations de membres à partir de classes sans utiliser de réflexion.MIT Vous pouvez le faire en créant une série de conseils de compilation pouvant mapper une classe et une liste de paramètres de fonction ou de type de retour.

En gros, vous devez créer des lambdas qui prennent des objets comme des paramètres et renvoient un objet. Utilisez ensuite une fonction générique que le compilateur voit AOT pour créer un cache de méthodes appropriées pour appeler le membre et jeter les paramètres. L'astuce consiste à créer des délégués ouverts et à les transmettre à travers une seconde Lamda pour se rendre à l'indice sous-jacent au moment de l'exécution.

Vous devez fournir les astuces pour chaque classe et chaque signature (mais pas toutes les méthodes ni tous les biens).

J'ai travaillé une classe ici qui fait cela, c'est un peu trop long pour énumérer dans ce poste.

En tests de performance, il ne s'agit pas d'où près de l'exemple ci-dessus, mais il est générique, ce qui signifie qu'il fonctionne dans les circonstances dont j'avais besoin. Performance autour de 4,5x sur la lecture d'une propriété par rapport à invoquer.


0 commentaires