为什么后续的直接方法调用比第一次调用快得多
本文关键字:调用 第一次 快得多 方法 为什么 | 更新日期: 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传递