【问题标题】:What is best way to measure the time cycles for a C# function?测量 C# 函数的时间周期的最佳方法是什么?
【发布时间】:2012-04-08 17:46:25
【问题描述】:

真的,我正在寻找一个好的函数,它可以准确地测量 Windows 操作系统下给定 C# 函数的时间周期。我尝试了这些功能,但它们都没有得到准确的测量:

DateTime StartTime = DateTime.Now;      
TimeSpan ts = DateTime.Now.Subtract(StartTime);
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
//code to be measured
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed; 

真的,每次我打电话给他们,他们都会给我不同的时间来完成相同的功能

如果有人知道准确测量耗时的更好方法,请帮助我,非常感谢

【问题讨论】:

    标签: c#


    【解决方案1】:

    秒表是测量功能执行所需时间的推荐方法。由于各种软件和硬件因素,每次运行都不会相同,这就是为什么性能分析通常是在大量运行上进行并且时间被平均化的原因。

    【讨论】:

    • 感谢您的回复......您是否听说过任何方法可以仅测量我的代码进程的时钟周期而不受其他进程的影响,而不是在大量运行中平均时间?
    【解决方案2】:

    “他们给我不同的时间来完成相同的功能”——这是意料之中的。事情会发生波动,因为您不是系统上运行的唯一进程。

    在一个大循环中运行您想要计时的代码以平均所有波动(将总时间除以循环数)。

    Stopwatch 是一个准确的计时器,在大多数情况下都足够了。

    const int numLoops = 1000000;   // ...or whatever number is appropriate
    
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();
    
    for (int i = 0; i < numLoops; i++)
    {
        // code to be timed...
    }
    
    stopWatch.Stop();
    TimeSpan elapsedTotal = stopWatch.Elapsed;
    double timeMs = elapsedTotal.TotalMilliseconds / numLoops;
    

    【讨论】:

    • +1,我在测量时总是将当前进程/线程优先级设置为最高。
    • 感谢您的回复,但我不认为我可以在循环中重复我的代码 1000000 次,因为我的代码很长,等待的时间太长了......有什么办法可以只测量我的代码进程的时钟周期,不受其他进程的影响?
    • 减少循环的大小,比如 1000 或 10000
    【解决方案3】:

    黄金标准是使用StopWatch。这是一个高分辨率的计时器,效果很好。

    我建议您使用.Elapsed.TotalMilliSeconds 检查经过的时间,因为您得到的是double,而不是.Elapsed.MilliSeconds,后者为您提供int。这可能会影响您的结果。

    此外,您可能会发现在计时测试期间会发生垃圾收集,这些可能会显着改变结果时间。在计时测试之前和之后检查 GC 收集计数并在发生任何垃圾收集时丢弃结果很有用。

    否则,您的结果可能会因为其他线程和进程在您的测试期间接管 CPU 和其他系统资源而有所不同。除了多次运行测试并通过计算平均值和标准偏差时间等对结果进行统计分析之外,您在这里无能为力。

    我希望这会有所帮助。

    【讨论】:

    • 感谢您的回复......您是否听说过任何方法可以仅测量我的代码进程的时钟周期而不受其他进程的影响,而不是在大量运行中平均时间?
    • @Duaa - AFAIK 无法确保这种情况,因为您首先需要操作系统进程来允许您的代码运行。如果您可以阻止它们,那么您的代码也会停止,您将无法进行任何计时。您必须在测试中允许其他进程和线程。这就是您需要使用统计数据的原因。
    【解决方案4】:

    虽然您可以以时钟周期来衡量您的代码,但它仍然会像以秒为单位衡量一样容易发生变化,而且用处不大(因为秒即使不是更好,也是一个单位)测量比时钟周期)。获得不受其他进程影响的测量的唯一方法是确保没有进程在运行,而您不能在 Windows 上这样做——操作系统本身将始终运行某些事情,因为它不是单进程操作系统.

    最接近您想要的测量结果是构建并运行您的代码as described here。然后,您可以通过在代码开头设置断点,然后单步执行来查看您想要计时的方法的 JIT 代码的 x86 程序集。您可以在 Intel 架构手册中交叉引用每条 x86 指令及其周期时序,并将它们相加以获得准确的周期计数。

    当然,这非常痛苦,而且基本上没用。它也可能因代码更改而失效,导致 JIT 采用稍微不同的方法从您的 IL 生成 x86。

    【讨论】:

      【解决方案5】:

      您需要分析器来测量代码执行情况(请参阅What Are Some Good .NET Profilers? 以开始您的搜索)。

      查看您的 cmets 并不清楚您要优化什么。通常,当您的代码执行 1000 次并且纯粹受 CPU 限制时,您需要向下测量 CPU 时钟周期,在其他情况下,每个函数的执行时间通常就足够了。但是您是说您的代码运行速度太慢,无法使用秒表计算平均时间。

      您还需要确定 CPU 是否是您的应用程序的瓶颈,或者是否有其他原因使其变慢。查看 TaskManager 中的 CPU % 可以为您提供有关它的信息 - 少于 100% 的 CPU 使用率几乎可以保证有其他东西(即网络或磁盘活动)会使程序变慢。

      基本上,提供有关您尝试衡量以实现性能目标的代码类型的更多详细信息将使您的帮助更加轻松。

      【讨论】:

      • 感谢您的回复......我试图测量它的时间是我在 C# 中编写的修改后的字符串匹配算法,我想将它的性能与其他字符串匹配算法进行比较,特别是对于time measurmenet,确保我修改后的字符串匹配算法比其他算法更快...非常感谢
      【解决方案6】:

      回应其他人:秒表类是执行此操作的最佳方式。

      回答您关于仅测量时钟周期的问题:您在现代处理器上的多任务操作系统上运行这一事实使得测量时钟周期几乎毫无用处。上下文切换很有可能从处理器缓存中删除您的代码和数据,同时操作系统可能会决定交换您的工作集。

      处理器可以决定根据缓存等待或内存访问对指令重新排序,并在等待时执行它可以执行的操作。或者如果它在缓存中,它可能不会。

      因此,简而言之,执行多次运行并将它们平均化确实是唯一的方法。

      为了在时间上减少抖动,您可以提升线程/进程的优先级,但这可能会导致一系列其他问题(碰撞到实时优先级,陷入长循环基本上会停止所有其他处理。如果发生错误,并且您陷入无限循环,您唯一的选择是重置按钮),并且根本不推荐,尤其是在用户计算机上或生产环境中。而且由于您无法在重要的地方执行此操作,因此它会使您在机器上运行的基准测试以及任何优先修改都无效。

      【讨论】:

        【解决方案7】:

        如何使用Environment.TickCount 捕获开始和结束然后到TimeSpan.FromTicks() 上呢?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-04
          • 2016-01-07
          • 1970-01-01
          • 2020-03-03
          • 2012-09-21
          • 1970-01-01
          • 2010-09-29
          • 2018-04-27
          相关资源
          最近更新 更多