由于頻繁地使用反射會影響性能,所以ASP.NET MVC采用了表達式樹的方式來執行目標Action方法。具體來說,ASP.NET MVC會構建一個表達式來體現針對目標Action方法的執行,并且將該表達式編譯成可執行代碼。編譯后的可執行代碼體現為一個委托對象,該委托對象會被緩存起來以用于針對同一個Action方法的執行。為了讓大家能夠和直觀地理解兩種(直接利用反射和利用表達式編譯后的委托對象)方法執行在性能上的差異,我們來做一個簡單的實例演示。我們在一個控制臺應用中定義了如下一個Foobar類型,它的Invoke方法就是我們需要測試的目標方法。簡單起見,我們沒有為它定義任何參數,方法本身也不需要執行任何具體操作。
1: public class Foobar
2: {
3: public void Invoke(){}
4: }
具體的測試程序如下所示。三個靜態屬性Target、Method和Executor分別代表執行的目標對象、目標方法和表達式編譯后生成的委托對象,后者通過調用靜態方法CreateExecutor方法創建。
1: class Program
2: {
3:
4: public static Foobar Target { get; private set; }
5: public static MethodInfo Method { get; private set; }
6: public static Action<Foobar> Executor { get; private set; }
7:
8: private static object[] args = new object[0];
9:
10: private static Action<Foobar> CreateExecutor(MethodInfo method)
11: {
12: ParameterExpression target = Expression.Parameter(typeof(Foobar),"target");
13: Expression expression = Expression.Call(target, method);
14: return Expression.Lambda<Action<Foobar>>(expression, target).Compile();
15: }
16:
17: static Program()
18: {
19: Target = new Foobar();
20: Method = typeof(Foobar).GetMethod("Invoke");
21: Executor = CreateExecutor(Method);
22: }
23:
24: static void Main()
25: {
26: Console.WriteLine("{0,-10}{1,-12}{2}", "Times", "Reflection", "Expression");
27: Test(100000);
28: Test(1000000);
29: Test(10000000);
30: }
31:
32: private static void Test(int times)
33: {
34: Stopwatch stopwatch = new Stopwatch();
35:
36: stopwatch.Start();
37: for (int i = 0; i < times; i++)
38: {
39: Method.Invoke(Target, args);
40: }
41: long elapsed1 = stopwatch.ElapsedMilliseconds;
42:
43: stopwatch.Restart();
44: for (int i = 0; i < times; i++)
45: {
46: Executor(Target);
47: }
48: long elapsed2 = stopwatch.ElapsedMilliseconds;
49:
50: Console.WriteLine("{0,-10}{1,-12}{2}", times, elapsed1, elapsed2);
51: }
52: }
測試方法Test的參數times表示我們執行目標方法的次數。在該方法中,我們調用MethodInfo對象的Invoke方法以反射的形式執行目標方法,然后利用Executor屬性表示的委托對象來執行目標方法,并將它們執行的時間(以毫秒為單位)輸出來。在作為程序入口的Main方法中,我們先后三個調用Test方法,并將執行目標方法的次數分別設置為100,000(十萬)、1,000,000(百萬)和10,000,000(千萬)。運行程序后我們會在控制臺上得到如下所示的輸出結果,可以看出直接采用反射方式執行某個方法確實在性能上要差一些,但是差異其實不算明顯。很多人總是覺得在程序中使用反射會對性能造成很大的影響,其實在我看來在很多情況下反射本身都不是造成性能瓶頸的元兇。
1: Times Reflection Expression
2: 100000 34 2
3: 1000000 273 28
4: 10000000 2627 284
文章列表