Maison  >  Article  >  développement back-end  >  Exemple de didacticiel d'appel direct et d'appel réfléchi

Exemple de didacticiel d'appel direct et d'appel réfléchi

零下一度
零下一度original
2017-06-23 15:01:001678parcourir

Beaucoup de gens disent que l'utilisation de la réflexion entraînera des problèmes de performances. Dans quelle mesure cela sera-t-il plus lent que de l'appeler directement ?

Appel direct vs appel réfléchi

Écrivons une démo pour vérifier la différence de performances entre l'appel direct et l'appel réfléchi. Le code est le suivant :

 1 namespace ConsoleApplication7 2 { 3     class Program 4     { 5         static void Main(string[] args) 6         { 7             //比较直接调用和反射调用的性能差异 8             //7ms vs 365ms 9             int times = 1000000;10             var program = new Program();11             CodeTimerHelper.Initialize();12 13             CodeTimerHelper.Time("直接调用", times, () =>14             {15                 program.Call();16             });17 18             var t = typeof(Program);19             var obj = Activator.CreateInstance(t);20             CodeTimerHelper.Time("反射调用", times, () =>21             {22                 t.InvokeMember("Call", BindingFlags.InvokeMethod, null, obj, null);23             });24 25             Console.ReadKey();26         }27 28         /// <summary>29         /// 测试方法30         /// </summary>31         public void Call()32         {33         }34 35     }36 }

Résultats des tests :

À en juger par les résultats de 1 million d'appels, c'est bien comme beaucoup de personnes l'ont dit,

Il existe une différence d'un ordre de grandeur en termes de performances entre les deux.

Pourquoi y a-t-il une perte de performance en réflexion

Puisqu'il y a une perte en performance de réflexion, où est la perte spécifique ?

1. La réflexion est basée sur l'assemblage et les métadonnées. Lors de l'utilisation de la réflexion, les métadonnées seront recherchées et les métadonnées sont basées sur des chaînes et ne peuvent pas être précompilées, cette série d'opérations a donc un impact.

2. Un grand nombre de boxing et unboxing ont également un impact sur les performances. Comme nous ne connaissons pas le type de cible et que les paramètres passés à la méthode sont généralement de type objet, il y aura beaucoup de boxing et de unboxing.

Solution d'optimisation des performances de réflexion

Nous savons déjà qu'il existe des problèmes de performances liés à l'utilisation de la réflexion, mais dans certains scénarios, nous devons utiliser la technologie de réflexion, nous devons donc trouver des moyens pour optimiser les performances de réflexion.

Nous citons ici la classe d'arbre d'expression System.Linq.Expressions.Expression divulguée par Lao Zhao et la comparons avec l'appel direct :

1 //3,基于表达式树2 var methodInfo = t.GetMethod("Call");3 var executor = new DynamicMethodExecutor(methodInfo);4 CodeTimerHelper.Time("Dynamic executor", times, () =>5 {6     executor.Execute(obj, null);7 });

Résultats des tests :

Wow, pour le même million d'appels, les performances d'utilisation de DynamicMethodExecutor sont presque les mêmes que appel direct.

Ci-joint le code d'encapsulation de DynamicMethodExecutor :

 1 /// <summary> 2 ///  3 /// </summary> 4 public class DynamicMethodExecutor 5 { 6     private Func<object, object[], object> m_execute; 7  8     public DynamicMethodExecutor(MethodInfo methodInfo) 9     {10         this.m_execute = this.GetExecuteDelegate(methodInfo);11     }12 13     public object Execute(object instance, object[] parameters)14     {15         return this.m_execute(instance, parameters);16     }17 18     private Func<object, object[], object> GetExecuteDelegate(MethodInfo methodInfo)19     {20         // parameters to execute21         ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");22         ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");23 24         // build parameter list25         List<Expression> parameterExpressions = new List<Expression>();26         ParameterInfo[] paramInfos = methodInfo.GetParameters();27         for (int i = 0; i < paramInfos.Length; i++)28         {29             // (Ti)parameters[i]30             BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));31             UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);32             parameterExpressions.Add(valueCast);33         }34 35         // non-instance for static method, or ((TInstance)instance)36         Expression instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceParameter, methodInfo.ReflectedType);37 38         // static invoke or ((TInstance)instance).Method39         MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);40 41         // ((TInstance)instance).Method((T0)parameters[0], (T1)parameters[1], ...)42         if (methodCall.Type == typeof(void))43         {44             Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceParameter, parametersParameter);45             Action<object, object[]> execute = lambda.Compile();46             return (instance, parameters) =>47             {48                 execute(instance, parameters);49                 return null;50             };51         }52         else53         {54             UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));55             Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceParameter, parametersParameter);56             return lambda.Compile();57         }58     }

En plus de la méthode d'utilisation de l'arborescence d'expression Linq pour générer Delegate, il y a Il existe également des méthodes telles que CodeDom génère du code et le compile dynamiquement, ou utilise Emit pour écrire IL directement afin d'améliorer les performances de réflexion, mais relativement parlant, la méthode ci-dessus est la plus simple.

À ce stade, le résumé de l'ensemble de la réflexion est terminé !

Article de référence

Appel direct de méthodes, appel de réflexion et... Appel d'expression lambda

Série de révision des connaissances de base en C# 15 : Réflexion

2. Qu'est-ce que la réflexion et ce que la réflexion peut faire

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn