>백엔드 개발 >C#.Net 튜토리얼 >직접 통화 및 반사 통화 예시 튜토리얼

직접 통화 및 반사 통화 예시 튜토리얼

零下一度
零下一度원래의
2017-06-23 15:01:001742검색

많은 사람들이 리플렉션을 사용하면 성능 문제가 발생한다고 말합니다. 직접 호출하는 것보다 얼마나 느려질까요? 아래에서 테스트해 보겠습니다.

직접 호출 vs 반사 호출

직접 호출과 반사 호출의 성능 차이를 확인하기 위해 데모를 작성해 보겠습니다. 코드는 다음과 같습니다.

 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 }

테스트 결과:

100만 호출에서 결과는 많은 사람들이 말했듯이 둘 사이의 성능에 큰 차이가 있음을 보여줍니다.

반영에 성능 손실이 있는 이유는 무엇인가요?

반영 성능에 손실이 있는데 구체적인 손실은 어디에 있나요?

1. 리플렉션은 어셈블리 및 메타데이터를 기반으로 합니다. 메타데이터는 문자열을 기반으로 하며 미리 컴파일할 수 없으므로 이러한 일련의 작업은 성능에 영향을 미칩니다.

2. 대량의 복싱과 언박싱도 성능에 영향을 미칩니다. 우리는 대상 유형을 모르고 메소드에 전달된 매개변수가 일반적으로 객체 유형이므로 박싱과 언박싱이 많이 발생합니다.

반사 성능 최적화 솔루션

우리는 이미 반사를 사용할 때 성능 문제가 있다는 것을 알고 있지만 일부 시나리오에서는 반사 기술을 사용해야 하므로 반사 성능을 최적화하는 방법을 찾아야 합니다.

여기에서는 Lao Zhao가 공개한 System.Linq.Expressions.Expression 표현식 트리 클래스를 인용하고 이를 직접 호출과 비교합니다.

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 });

테스트 결과:

와우, 동일한 100만 호출에도 DynamicMethodExecutor를 사용한 호출 성능은 직접 호출 성능과 거의 같습니다.

첨부된 것은 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     }

linq의 표현식 트리를 사용하여 Delegate를 생성하는 방법 외에도 CodeDom과 같은 방법으로 코드를 생성하고 동적으로 컴파일하거나 Emit를 사용하여 Reflection 성능을 향상시키기 위해 IL을 직접 작성하지만 상대적으로 말하면 위의 방법이 가장 간단합니다.

이제 전체 리플렉션 요약이 완성되었습니다!

참고자료

메서드 직접 호출, 리플렉션 호출 그리고... 람다 표현식 호출

C# 기본 지식 복습 시리즈 15: 리플렉션

2. 반성이란 무엇인가, 반성은 무엇을 할 수 있는가

위 내용은 직접 통화 및 반사 통화 예시 튜토리얼의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.