【问题标题】:The overall performance where the method is placed in a code方法放置在代码中的整体性能
【发布时间】:2013-08-25 18:31:04
【问题描述】:

考虑这段代码:

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

method1 得到 00:00:00.0000019 秒的调用时间。

method2 得到 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();

然后重新运行测试。

method1 获得 00:00:00.0000006 秒的调用时间。

method2 获取 00:00:00.0000019 秒进行调用。

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

【问题讨论】:

  • 等等,你是说你调用的第一个方法比较慢吗?因为看起来您的第二个示例输出是第一个复制粘贴的,而不是您在更改 调用 的顺序后运行代码的结果。 (它仍然在method2 之前列出method1。)在这种情况下,呃,在第二次调用时,它的代码可能在CPU 缓存中或者已经JITted。
  • 同意这2个方法有相同的calculations,所以第一次调用总是比第二次慢,因为calculations可能在第一次调用后缓存在CPU缓存中。

标签: c#


【解决方案1】:

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

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

另外:

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

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

【讨论】:

  • 我在函数中写了一个循环 0 到 100000 并再次得到相同的结果第一种方法获得更多时间
  • @ShahroozJefriㇱ 在优化期间无法删除从 0 到 100000 的循环。
  • @ShahroozJefriㇱ:如果你调用方法两次,会发生这种情况吗?请记住,还有 JIT 编译时间......以及对没有用处的循环的优化,正如millimoose 所说。我建议您使用您认为是有效的测试来编辑您的问题。您可能想阅读 Eric Lippert 的基准测试系列,从这里开始:tech.pro/blog/1293/c-performance-benchmark-mistakes-part-one
  • @JonSkeet 在 IDEone 中戳这个我认为 OP 只是措辞不好,这意味着第一个被调用的方法更慢。
  • @millimoose:这很可能与 JIT 编译有关。这就是问题所在 - 基准测试中存在足够多的风险,编写一个好的基准测试很棘手,我们需要先查看 OP 认为“完成”的完整代码,然后才真正值得将它分开太多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-05
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多