【问题标题】:Stopwatch weird behavior秒表奇怪的行为
【发布时间】:2010-11-03 15:35:16
【问题描述】:
            Stopwatch sw = new Stopwatch();
            for (int i = 0; i < lines.Length; i++)
            {
                sw.Start();
                fn(); //call function
                sw.Stop();

            }
            Console.WriteLine(sw.ElapsedMilliseconds);


            long total =0;
            for (int i = 0; i < lines.Length; i++)
            {
                Stopwatch sw = Stopwatch.StartNew();
                fn(); //call function
                sw.Stop();
                total += sw.ElapsedMilliseconds;

            }
            Console.WriteLine(total);

输出不一样,你有什么解释吗?

【问题讨论】:

  • 对于任何合理的长度 fn()(值得分析),与循环相关的开销可以忽略不计,并且在任何情况下都小于与 Start 和 Stop 相关的开销。一方面,Start 和 Stop 都有方法调用开销(假设没有内联),而简单的 for 循环只是一个增量和比较分支。

标签: c# stopwatch


【解决方案1】:

撇开诸如您在第二个循环中创建大量对象的事实不谈,这很容易导致fn() 内的垃圾收集或其他东西实际上使得计时时间更长,您也只是在第二种情况下每次迭代都经过 毫秒

假设每次迭代需要 0.1 毫秒。第二个循环的总数将为 0,因为在每次迭代中,它会将经过的时间四舍五入为 0 毫秒。第一个循环跟踪经过的滴答声

抛开所有这些,无论如何,您都不应该如此频繁地启动和停止计时器 - 它弄乱您的结果。相反,在循环之前启动秒表一次,然后在循环之后停止。

如果您想消除循环的开销,只需为 empty 循环计时以找到开销,然后从包含实际工作的循环所花费的时间中减去该开销。现在它并不是真的相当那么简单,因为现实世界 CPU 的各种复杂性——比如缓存未命中——但坦率地说,微基准测试在这方面从来没有特别准确。它应该被用作指南,而不是其他任何东西。

【讨论】:

  • 这已经很老了,但我认为值得注意的是,这里秒表的典型用法是开始before循环并停止after 然后循环除以迭代次数 (lines.Length) 以获得 fn() 的平均时间。假设迭代次数很高,这应该是相当准确的,因为循环的开销很低,而且对于非常快速的函数,秒表粒度没有问题。
  • @Lummo:我已经为此添加了一句话。
【解决方案2】:

因为StartNew()Stop() 会产生开销。这就是您通常使用 100 或 1000 次迭代进行此类测试的原因:以最大限度地减少实际性能测量的性能开销。

【讨论】:

  • 我认为问题是由于 Skeet 提到的分辨率丢失
  • 创建在测量代码之外(在秒表上开始是在 StartNew 中完成的最后一件事),因此不会影响计时器。另一边的分辨率和四舍五入似乎是原因。正确答案似乎是 Jon Skeets 的答案 (stackoverflow.com/a/4088847/95008)。
【解决方案3】:

您可能遇到了系统计时器的粒度。有时计时一个微不足道的函数会返回 0 或 10 毫秒。此错误可能会在您的测试中叠加。

如果您将第一个循环运行两次或将第二个循环也运行两次,您可能会看到类似的结果。

【讨论】:

    【解决方案4】:

    循环的开销将大大小于重复停止/启动计时器的开销,甚至在重复创建新计时器的情况下更小。因此,我会在循环之前启动计时器并在循环之后结束它,然后将经过的时间除以迭代次数。它将为您提供更准确的结果。

    【讨论】:

    • 确实如此,但我只想衡量我的功能性能
    • 然后,正如 Jon 所说,测量一个空循环并从该测量值中减去。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多