3

考虑这段代码:

namespace FastReflectionTests
{
    public class Test
    {
        public void Method1()
        {
            var x = 10;
            var y = 20;
             if (x == 10 && y == 20)
            {

            }
        }

        public void Method2()
        {
            var x = 10;
            var y = 20;
            if (x == 10 && y == 20)
            {

            }
        }
    }
}

现在考虑 IL 代码:

这是方法1:

    instance void Method1 () cil managed 
    {
    // Method begins at RVA 0x3bd0
    // Code size 17 (0x11)
    .maxstack 2
    .locals init (
    [0] int32 x,
    [1] int32 y
    )

    IL_0000: ldc.i4.s 10
    IL_0002: stloc.0
    IL_0003: ldc.i4.s 20
    IL_0005: stloc.1
    IL_0006: ldloc.0
    IL_0007: ldc.i4.s 10
    IL_0009: bne.un.s IL_0010

    IL_000b: ldloc.1
    IL_000c: ldc.i4.s 20
    IL_000e: pop
    IL_000f: pop

    IL_0010: ret
    } // end of method Test::Method1

这是方法2:

    instance void Method2 () cil managed 
    {
    // Method begins at RVA 0x3bf0
    // Code size 17 (0x11)
    .maxstack 2
    .locals init (
    [0] int32 x,
    [1] int32 y
    )

    IL_0000: ldc.i4.s 10
    IL_0002: stloc.0
    IL_0003: ldc.i4.s 20
    IL_0005: stloc.1
    IL_0006: ldloc.0
    IL_0007: ldc.i4.s 10
    IL_0009: bne.un.s IL_0010

    IL_000b: ldloc.1
    IL_000c: ldc.i4.s 20
    IL_000e: pop
    IL_000f: pop

    IL_0010: ret
    } // end of method Test::Method2

方法 1 获取 00:00:00.0000019 秒进行调用。

方法 2 获取 00:00:00.0000006 秒进行调用。

我编写此代码进行测试

public class Program
    {
        private static void Main(string[] args)
        {
            var test = new Test();
            test.Method1();
            test.Method2();
            System.Console.ReadLine();
        }
    }


    public class Test
    {
        public void Method1()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            var x = 10;
            var y = 20;
            if (x == 10)
            {
                if (y == 20)
                {

                }
            }
            stopwatch.Stop();

            Console.WriteLine("Time Method1: {0}",
                stopwatch.Elapsed);
        }

        public void Method2()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            var x = 10;
            var y = 20;
            if (x == 10 && y == 20)
            {

            }
            stopwatch.Stop();
            Console.WriteLine("Time Method2: {0}",
                stopwatch.Elapsed);
        }
    }

我改变了method1和method2的位置。

 test.Method2();
 test.Method1();

并重新运行测试。

方法 1 获取 00:00:00.0000006 秒进行调用。

方法 2 获取 00:00:00.0000019 秒进行调用。

当我更改方法的位置时,第二种方法比第一种方法花费的时间更多!是什么原因?

4

1 回答 1

11

您正在对少量代码进行计时,以这样一种方式,任何数量的微小偶然事件都会干扰结果 - 页面错误或缓存未命中可能在此时变得相关......并且很容易受到影响方法的排序。

你真的应该对多个调用进行基准测试 - 或者以任何方式做足够的工作以花费合理的时间。任何测量时间少于一秒左右的基准都是可疑的,IMO。

此外:

  • 您几乎肯定不想包含 JIT 编译时间。
  • JIT 编译应该能够删除大部分时间基本上没有意义的代码。我通常会添加某种累加器并在测试结束时输出结果(在停止 之后Stopwatch)以保持 JIT 编译器“诚实”。

请参阅 Eric Lippert 的基准测试系列了解更多详细信息(以及 GC 等其他陷阱):

于 2013-08-24T10:44:17.703 回答