为什么后续的直接方法调用比第一次调用快得多

本文关键字:调用 第一次 快得多 方法 为什么 | 更新日期: 2023-09-27 17:59:50

正如MSDN的这篇文章中所解释的,当使用.NET Reflection API(如InvokeMember)时,由于元数据的缓存,第一个调用的运行时间要比后续调用长得多。

当我在不使用反射的情况下测试直接方法调用时,我在Mono和.NET4上也看到了类似的效果。

第一个数字是运算的结果,"-"之后的第二个数字是此运算所花费的时间(以毫秒为单位)。我使用了"<--"标记以标识第一个方法调用。

300 - 0.192 <--
300 - 0.004
300 - 0.004
-100 - 0.096 <--
-100 - 0.004
-100 - 0.004

为什么会这样?我可以理解第一次通话可能会慢一些,但慢50倍并不是我所期望的。

附件是获得此结果的源代码。

图书馆

namespace MyClass
{
    public class Calculator
    {
        public int Value1 {get; set;}
        public int Value2 {get; set;}
        public Calculator()
        {
            Value1 = 100;
            Value2 = 200;
        }
        public int Add(int val1, int val2)
        {
            Value1 = val1; Value2 = val2;
            return Value1 + Value2;
        }
        public int Sub(int val1, int val2)
        {
            Value1 = val1; Value2 = val2;
            return Value1 - Value2;
        }
    }
}

调用此库的代码

// http://msdn.microsoft.com/en-us/magazine/cc163759.aspx
using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using MyClass;
class TestOne
{
    static void DirectTest()
    {
        Stopwatch sw;
        Calculator t = new Calculator();
        sw = Stopwatch.StartNew();
        int value1 = t.Add(100,200);
        sw.Stop();
        double time1 = sw.Elapsed.TotalMilliseconds;
        sw = Stopwatch.StartNew();
        int value2 = t.Add(100,200);   
        sw.Stop();
        double time2 = sw.Elapsed.TotalMilliseconds;
        sw = Stopwatch.StartNew();
        int value3 = t.Add(100,200); 
        sw.Stop();
        double time3 = sw.Elapsed.TotalMilliseconds;
        Console.WriteLine("{0} - {1}", value1, time1);
        Console.WriteLine("{0} - {1}", value2, time2);
        Console.WriteLine("{0} - {1}", value3, time3);
        sw = Stopwatch.StartNew();
        value1 = t.Sub(100,200);
        sw.Stop();
        time1 = sw.Elapsed.TotalMilliseconds;
        sw = Stopwatch.StartNew();
        value2 = t.Sub(100,200);  
        sw.Stop();
        time2 = sw.Elapsed.TotalMilliseconds;
        sw = Stopwatch.StartNew();
        value3 =  t.Sub(100,200); 
        sw.Stop();
        time3 = sw.Elapsed.TotalMilliseconds;
        Console.WriteLine("{0} - {1}", value1, time1);
        Console.WriteLine("{0} - {1}", value2, time2);
        Console.WriteLine("{0} - {1}", value3, time3);
    }
    static void Main()
    {
        DirectTest();
        DirectTest();
    }
}

为什么后续的直接方法调用比第一次调用快得多

这是因为.NET应用程序使用的实时(JIT)编译方法。JIT编译器将MSIL字节码转换为机器代码一次,并且由于生成并缓存了本机版本,因此该代码的后续执行要快得多。

当你运行代码时,你会付出一次性的代价,但JIT编译器也可以对当前体系结构进行优化,如果代码从一开始就是本地的,它就无法进行优化。但是,您可以通过调用RuntimeHelpers.PrepareMethod.来强制JIT传递