.NET, Architecture, ALM, Cloud

Publicité

Performance du DynamicObject

 

Le DynamicObject (C# 4.0) peut s'avérer très utile mais il convient de l'utiliser avec précaution pour éviter de plomber les performances de son application. Examinons ses performances à la loupe.

public class TestObject : DynamicObject

{

     public dynamic Prop1 { get; set; }

 

     public override bool TrySetMember(SetMemberBinder binder, object value)

     {

         return true;

     }

}

 

Le but de nos premiers tests de performance va être d'appeler une propriété "Prop2" de notre DynamicObject "TestObject" via la méthode "TrySetMember". Commençons par la méthode classique, c'est-à-dire la reflection :

MethodInfo mi = typeof(TestObject).GetMethod("TrySetMember");

dynamic testObj = new TestObject();

for (int i = 0; i < 10000000; i++)

{

   mi.Invoke(testObj, new object[] { null, "test" });

}


Pour 10 millions d'itérations, ce code ne prends pas moins de 40 secondes à s'exécuter ! Utilisons à présent les fonctionnalités du mot clef dynamic qui va nous permettre d'appeler directement la propriété "Prop2" sans que notre compilateur préféré vérifie son accès et nous permette donc d'exécuter le programme :

dynamic dynamicObj = new TestObject();

for (int i = 0; i < 10000000; i++)

{

     dynamicObj.Prop2 = "test";

}


Toujours pour 10 millions d'itérations, ce code va s'exécuter en moyenne en 1.5 secondes contre les 40 secondes en reflection classique. Où est l'astuce ? Le compilateur va tout simplement générer du code en faisant appel à la DLR qui va permettre de compiler le code d'accès à la propriété à la volée :

dynamic testObj = new TestObject();

SetMemberBinder binder = (SetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.SetMember(

                CSharpBinderFlags.None,

                "Prop2",

                typeof(Program),

                new CSharpArgumentInfo[] {     CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),

      CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant |           CSharpArgumentInfoFlags.UseCompileTimeType, null) });

CallSite<Func<CallSite, object, string, object>> dynCallSite = CallSite<Func<CallSite, object, string, object>>.Create(binder);          

for (int i = 0; i < 10000000; i++)

{

     dynCallSite.Target.Invoke(dynCallSite, testObj, "test");

}


Après avoir crée notre Binder DLR sur notre propriété "Prop2", nous allons l'appeler via un CallSite qui va nous générer l'arbre d'expression puis le compiler. Ce même code s'exécute lui aussi en moyenne en 1.5 secondes. Pour se rendre compte du rôle du CallSite, écrivons le code équivalent en arbre d'expression :

ParameterExpression param = Expression.Parameter(typeof(TestObject), "testObj");

ParameterExpression param2 = Expression.Parameter(typeof(SetMemberBinder), "binder");

ParameterExpression param3 = Expression.Parameter(typeof(object), "value");


Action<TestObject, SetMemberBinder, object> assignProp2 = Expression.Lambda<Action<TestObject, SetMemberBinder, object>>(

                Expression.Call(param, mi, param2, param3),

                param, param2, param3).Compile();

for (int i = 0; i < 10000000; i++)

{

    assignProp2(testObj, binder, "test");

}


Vous l'avez compris il n'y pas de véritable révolution avec le mot clef dynamic mais il va tout simplement nous permettre de clarifier notre code et c'est encore une fois le compilateur qui va faire tout le travail pour appeler notre merveilleuse boite à outils DLR.

Mais attention à ne pas abuser avec son utilisation et à ne pas tout passer en dynamic ! Exemple :

dynamic testObj = new TestObject();

TestObject testObj2 = new TestObject();

for (int i = 0; i < 10000000; i++)

{

     testObj.Prop1 = "test";

}

 

for (int i = 0; i < 10000000; i++)

{

    testObj2.Prop1 = "test";

}


L'utilisation d'un type "dynamic" au lieu d'un type "TestObject" pour accéder à une propriété "Prop1" existante va prendre 4 fois plus de temps à l'exécution notamment à cause du code généré en plus par le compilateur et des casts supplémentaires.

 

 

 

Publicité
Retour à l'accueil
Partager cet article
Repost0
Pour être informé des derniers articles, inscrivez vous :
Commenter cet article