暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

优化委托的 DynamicInvoke

amazingdotnet 2020-04-19
347

优化委托的 DynamicInvoke

Intro

委托方法里有一个 DynamicInvoke
的方法,可以在不清楚委托实际类型的情况下执行委托方法,但是用 DynamicInvoke
去执行的话会比直接用 Invoke
的方法会慢上很多,差了两个数量级,所以在知道委托类型的情况下尽可能使用 Invoke
执行,但有时候我们并不知道委托的实际类型,比如在很多类库项目中可能并不是强类型的委托

优化方法

优化方法,直接执行委托的对应的方法, DynamicInvoke
实际也是调用的对应的方法,我们如果执行调用对应的方法就可以优化

  1. delegate func = (Func<string, string>)str=> "12345";

  2. string paramString = "321";


  3. // Invoke

  4. ((Func<string, string>)func).Invoke(paramString);


  5. // DynamicInvoke

  6. func.DynamicInvoke(new object[]{ paramString });


  7. // Method Invoke

  8. func.Method.Invoke(func.Target, new object[]{ paramString });

性能测试

下面做一个性能测试,测试代码如下:

  1. public class DelegateInvokeTest

  2. {

  3. private readonly Delegate _func, _func1;

  4. private readonly string parameter;

  5. private readonly int paramInt;


  6. public DelegateInvokeTest()

  7. {

  8. parameter = "Test";

  9. paramInt = 1;


  10. _func = (Func<string, string>)(str => str);

  11. _func1 = (Func<int, int>)(val => 0);

  12. }


  13. [Benchmark(Baseline = true)]

  14. public object Invoke()

  15. {

  16. return ((Func<string, string>)_func).Invoke(parameter);

  17. }


  18. [Benchmark]

  19. public object InvokeBoxing()

  20. {

  21. return ((Func<int, int>)_func1).Invoke(paramInt);

  22. }


  23. [Benchmark]

  24. public object DynamicInvoke()

  25. {

  26. return _func.DynamicInvoke(parameter);

  27. }


  28. [Benchmark]

  29. public object DynamicInvokeBoxing()

  30. {

  31. return _func1.DynamicInvoke(paramInt);

  32. }


  33. [Benchmark]

  34. public object MethodInfoInvoke()

  35. {

  36. return _func.Method?.Invoke(_func.Target, new object[] { parameter });

  37. }


  38. [Benchmark]

  39. public object MethodInfoInvokeBoxing()

  40. {

  41. return _func1.Method?.Invoke(_func1.Target, new object[] { paramInt });

  42. }


  43. [Benchmark]

  44. public object ReflectInvoke()

  45. {

  46. var funcType = typeof(Func<,>).MakeGenericType(typeof(string), typeof(string));

  47. var method = funcType.GetProperty("Method")?.GetValueGetter()?.Invoke(_func) as MethodInfo;

  48. var target = funcType.GetProperty("Target")?.GetValueGetter()?.Invoke(_func);

  49. return method?.Invoke(target, new object[] { parameter });

  50. }


  51. [Benchmark]

  52. public object ReflectInvokeBoxing()

  53. {

  54. var funcType = typeof(Func<,>).MakeGenericType(typeof(string), typeof(int));

  55. var method = funcType.GetProperty("Method")?.GetValueGetter()?.Invoke(_func1) as MethodInfo;

  56. var target = funcType.GetProperty("Target")?.GetValueGetter()?.Invoke(_func1);

  57. return method?.Invoke(target, new object[] { paramInt });

  58. }

  59. }

测试结果如下:

由上面的结果,我们可以看出来,直接调用方法的性能虽然还是比 Invoke
慢上好多,但是相比 DynamicInvoke
已经优化 70% 左右,对于有装箱操作的性能会稍差一些,比 DynamicInvoke
优化可达 44% 左右。

Reference

  • https://github.com/WeihanLi/PerformanceTest/blob/master/PerformanceTest/ReflectionTests/DelegateInvokeTest.cs

  • https://github.com/WeihanLi/PerformanceTest/blob/master/PerformanceTest/BenchmarkDotNet.Artifacts/results/PerformanceTest.ReflectionTests.DelegateInvokeTest-report-github.md


文章转载自amazingdotnet,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论