Discussion.NET reflection mechanism performance optimization with example download

  • 2020-05-17 05:04:50
  • OfStack

Maybe you're starting to twitch when it comes to reflexes. Because the most notorious thing in managed languages is reflection! Its performance is so low that in many cases it is unbearable. But don't worry too much, today Chen is going to share 1 how to optimize reflection!

An overview of the
There are two ways of reflection optimization involved in this paper:

Optimize by creating a delegate through Delegate.CreateDelegate ()
Optimize through the dynamic runtime of.NET4
If you know of other more effective ways to optimize, please let us know!

The preparatory work
Today we're going to compare five different ways of calling object members, which is a performance measure.

Before we start, let's first define a simple object and a method for testing:
 
namespace ReflectionOptimization 
{ 
public sealed class TestObject 
{ 
public int Add(int a, int b) 
{ 
//  A simple demo  
return a + b; 
} 
} 
} 

This class is very simple, providing only one method that returns the sum of two integers. Let's take a look at the code that performs the time measurement. It's simple, and you're probably already familiar with it:
 
private static double _Run(string description, Action<int, int> action, int a, int b) 
{ 
if (action == null) throw new ArgumentNullException("action"); 

//  Start timer  
var stopwatch = Stopwatch.StartNew(); 

//  Run the code to be measured  
action(a, b); 

//  Termination of the timing  
stopwatch.Stop(); 

//  The output  
Console.WriteLine("{0}: {1}", description, stopwatch.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture)); 

//  Return execution time  
return stopwatch.Elapsed.TotalMilliseconds; 
} 

The above method of measuring time returns the execution time, because we will use this value later, and take an average value after several executions, in order to test the fairness and authority.

coded
First let's look at the implementation of native reflection:
 
var obj = new TestObject(); 
var add = obj.GetType().GetMethod("Add"); 

for (var i = 0; i < _TIMES; i++) add.Invoke(obj, new object[] {a, b}); 

Then let's look at the implementation of.NET4 dynamic programming:
 
dynamic obj = new TestObject(); 

//  Do you find this code super simple?  
for (var i = 0; i < _TIMES; i++) obj.Add(a, b); 

Finally, let's look at how to use delegation to optimize reflection:
 
//  entrust  
public delegate int AddMethod(int a, int b); 

//  implementation  
var obj = new TestObject(); 
var objType = obj.GetType(); 
var add = objType.GetMethod("Add"); 
var d = (AddMethod)Delegate.CreateDelegate(typeof(AddMethod), obj, add); 

for (var i = 0; i < _TIMES; i++) d(a, b); 

The code above looks a few more lines and requires a custom delegate, which is a bit cumbersome to write. Therefore, our test code also implements another form, which is also a delegate:

var d = (Func < TestObject, int, int, int > )Delegate.CreateDelegate(typeof(Func < TestObject, int, int, int > ), add);

Test summary
We first ran the entire test code five times in Debug mode, then recorded the averages separately, and then repeated the test in Release mode.

The test process is no longer elaborated, and the test results are summarized as follows:

Debug mode:

Call way The first The 2nd The third time 4 times The fifth time Generic Call 1.022425 1.012885 0.990775 1.020950 1.046880 Reflection 147.489220 146.012010 142.690080 139.189335 141.663475 dynamic 9.645850 9.979965 9.307235 9.532665 9.730030 Func 1.201860 1.214800 1.170215 1.189280 1.239485 Delegate 1.062215 1.061635 1.067510 1.047180 1.075190

Release mode:

Call way The first The 2nd The third time 4 times The fifth time Generic Call 0.745600 0.741365 0.722145 0.732630 0.725645 Reflection 141.778260 142.855410 142.346095 139.649990 138.541285 dynamic 9.631460 10.341850 9.284230 9.457580 9.060470 Func 0.882100 0.852680 0.875695 0.854655 0.831670 Delegate 0.710280 0.722465 0.723355 0.727175 0.693320

Comments & conclusions:

After using the delegate optimization reflection, its performance is not much different from that of direct invocation, and remains within the same order of magnitude. This scheme is recommended when the performance is extremely demanding. The performance difference between explicit delegation (Delegate) and anonymous delegation (Func) is very insignificant, but the performance of explicit delegation is still better by 1 point. Native delegates are two orders of magnitude slower than direct calls, and the performance difference is 200 times greater! The dynamic programming syntax of NET 4 is quite simple, and its performance is only an order of magnitude better than direct invocation, which is recommended because of its simple syntax! Native reflection doesn't differ much between Debug and Release modes, but other modes have more obvious optimizations (think why); While our tests today don't necessarily mean that reflection optimization can be as good as direct invocation, they can at least go some way to beating the rumor that reflection 1 is going to be slow (hee hee)!
Code download: talk about reflection optimization

Related articles: