【问题标题】:What is the best way to measure how long code takes to execute?衡量代码执行时间的最佳方法是什么?
【发布时间】:2011-01-05 13:17:29
【问题描述】:

我正在尝试确定哪种删除字符串的方法是最快的

我只是获取开始结束时间并显示差异。

但结果是如此多种多样,例如如下所示,相同的方法可能需要 60 毫秒到 231 毫秒。

有什么更好的方法可以获得更准确的结果?

alt text http://www.deviantsart.com/upload/1q4t3rl.png

using System;
using System.Collections;
using System.Collections.Generic;

namespace TestRemoveFast
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int j = 0; j < 10; j++)
            {
                string newone = "";
                List<string> tests = new List<string>();
                for (int i = 0; i < 100000; i++)
                {
                    tests.Add("{http://company.com/Services/Types}ModifiedAt");
                }

                DateTime start = DateTime.Now;
                foreach (var test in tests)
                {
                    //newone = ((System.Xml.Linq.XName)"{http://company.com/Services/Types}ModifiedAt").LocalName;
                    newone = Clean(test);
                }

                Console.WriteLine(newone);
                DateTime end = DateTime.Now;
                TimeSpan duration = end - start;
                Console.WriteLine(duration.ToString());
            }

            Console.ReadLine();
        }

        static string Clean(string line)
        {
            int pos = line.LastIndexOf('}');
            if (pos > 0)
                return line.Substring(pos + 1, line.Length - pos - 1);
                //return line.Substring(pos + 1);
            else
                return line;
        }
    }
}

【问题讨论】:

  • 我不认为测量本身有任何不准确之处。你可能的意思是,没想到会有这么大的分散。我想您必须确保计算机上没有其他程序正在使用您所有的 cpu 时间或内存。
  • 请注意,由 DateTime 测量的“挂钟时间”仅精确到 30 毫秒。 DateTime 用于表示墙上的时钟或您上次编辑文件的时间;它不必具有纳秒级精度,所以它没有。

标签: c# performance


【解决方案1】:

您应该使用System.Diagnostics.Stopwatch,并且您可能需要考虑一个大样本。例如,重复这个测试 10,000 次,然后平均结果。如果你科学地思考它,它是有道理的。样本越大越好。您可以通过这种方式清除很多边缘情况,并真正了解核心性能是什么样的。

要考虑的另一件事是,JIT 编译和对象创建肯定会影响您的结果,因此请确保您在适当的时间启动和停止您的秒表,并在开始之前调用您想要测试的方法至少一次测试。尽量将您想要测试的部分与代码的其余部分隔离开来。

【讨论】:

  • 另外,我通常会确保调用了测试方法以避免在测量中包含 JIT 编译时间。
  • 是的,很好,弗雷德里克。您要确保将测试分解为您想要监控的部分。很多时候人们不会考虑创建新对象和 JIT 会如何影响结果。
  • 肯定添加重复。在小于 10 秒的块中,系统将 CPU 时间交给其他任务可能会严重影响测试性能。约 10 分钟的测试更可靠。此外,终止所有其他 CPU 密集型和磁盘密集型进程。
  • 有没有好的随机化技术?简单地将每种方法运行 10,000 次并进行比较可能会因序列相关而产生高度偏差。每次运行之间需要交替或随机化。
【解决方案2】:

您可以使用Stopwatch 类。

秒表通过以下方式测量经过的时间 计算底层证券中的计时器滴答声 计时器机制。如果安装了 硬件和操作系统支持 高分辨率性能计数器, 然后秒表类使用它 计数器来测量经过的时间。

var sw = new Stopwatch();

sw.Start();
// ...
sw.Stop();

【讨论】:

    【解决方案3】:

    您可能需要在此处应用一些统计技术来消除差异。尝试运行同一段代码 1000 次,然后取平均时间,然后进行比较。模拟通常采用某种方法来“清理”数字,这就是其中之一。

    【讨论】:

      【解决方案4】:

      如果您只是担心在自己的代码中对其进行测试...使用System.Diagnostics.Stopwatch

      我通常更喜欢从我的代码中分离出这种东西并使用真正的 Profiler,例如 RedGate's Performance Profiler

      【讨论】:

        【解决方案5】:

        三个简单的注意事项:

        1. 使用System.Diagnostics.Stopwatch

        2. 不要在同一输入上对代码进行一百万次分析。尝试找到您预期的输入分布和配置文件。这是真实世界输入的概况,而不是实验室输入。

        3. 在进入分析循环之前运行一次Clean 方法以消除 JITting 时间。有时这很重要。

        其中,注释 1. 和 2. 是迄今为止最重要的。

        如果您不使用高分辨率计时器,您的分析结果将毫无意义。请注意,我们不会使用 water clock 计时 Usain Bolt

        如果您不在真实世界的输入上进行测试,那么您的分析结果将毫无意义。请注意,碰撞测试会以 35 MPH 的速度撞上其他汽车,而不是以 5 MPH 的速度撞上由棉花糖制成的墙壁。

        因此:

        // expectedInput is string[1000000]
        // populate expectedInput with real-world input
        Clean(expectedInput[0]);
        Stopwatch sw = new Stopwatch();
        sw.Restart();          //So you dont have to call sw.Reset()
        for (int i = 0; i < 1000000; i++) {
            string t = Clean(expectedInput[i]);
        }
        sw.Stop();
        Console.WriteLine(sw.Elapsed);
        

        一个复杂的音符:

        如果您确实需要进行分析,请获取像 ANTS 这样的分析器。

        【讨论】:

        • 我在任何地方都找不到 Clean 方法,在 MSDN 上也找不到?
        • @didibus: Clean 恰好是 OP 进行基准测试的方法的名称;这就是为什么我们在这里引用Clean
        【解决方案6】:

        通常:不要查看挂钟时间,而是查看进程消耗的 CPU 时间来确定它运行了多长时间。特别是对于只是计算的事情,这更加可靠,因为它不会受到同时运行的其他进程的影响。

        【讨论】:

        • 然而,这可能会有问题,因为 CPU 时间也不会计算等待 I/O 或页面错误 (?) 等事情。这些会影响实际系统的性能,需要加以考虑。
        • 这就是为什么我注意到这主要仅用于仅计算任务。
        【解决方案7】:

        所有基于时钟的方法的问题在于,您永远无法确定自己在计时。无论您是否意识到,您都可以在时间安排中加入:

        • 在操作系统抢占您的处理器时延迟;
        • 上下文切换
        • 在程序等待数据时停止;
        • 等等。

        我并不是说所有这些都适用于这个特定的时间,而是一般的时间。因此,您应该通过考虑替代代码执行多少基本操作来补充您所做的任何时间 - 一些复杂性的考虑,而不是忽略(就像我们通常做的那样)常数项。

        在您的特定情况下,您应该瞄准更长的执行时间;当你的时间是亚秒级时,操作系统极有可能把你弄得乱七八糟。所以运行 10^6 次迭代并使用足够多的运行次数的平均值来为您提供有意义的平均值和方差计算。并确保,如果您采用这种方法,您不会因为在第一次试验结束后已经加载数据而无意中加速了第二次试验。您必须确保 10^6 次试验中的每一次都与第一次试验完全相同。

        玩得开心

        标记

        【讨论】:

          【解决方案8】:

          我必须高度推荐包含在Visual Studio Team Suite or Development Edition 中的分析器(或者即将推出的Visual Studio 2010 Premium or Ultimate 甚至更好)作为最佳方式。它是高度可配置的、极其强大的、简单易用的、非常快速的,并且可以与本机代码和托管代码一起使用。我不熟悉ANTS 的工作流程,但这似乎是另一种选择。毫无疑问,对于关心应用程序性能的开发人员来说,唯一选项是使用分析器。 没有替代品,而且你真的不能接受任何致力于性能的商业开发人员会认真地放弃分析器。

          但是,如果您对以下任一方面的测量感兴趣,您可能无法访问此类分析器,在这种情况下,秒表类可以构成您测量技术的基础:

          • 对项目绩效感兴趣的学生或业余爱好者(出于经济原因,可能无法使用商业分析器)
          • 在公开发布的应用程序中,您可能希望对在 UI 线程上执行的代码部分进行计时并报告统计信息,以确保操作不会对您的任何用户造成明显的延迟。 Office 团队使用这样的方法取得了巨大的成功(Outlook 2007 SP2 有人吗?),我知道 Visual Studio 团队至少在 2010 版本中有此代码。

          【讨论】:

            【解决方案9】:

            在操作系统的底层进行了大量活动,这很可能会打乱您的时间测量。为了提高测量时间的准确性,您应该多次执行测试并从最终结果中删除最小和最大时间。这种方法将排除大多数可能影响代码执行时间的外部因素,并且在大多数情况下都能很好地为您服务。 Stopwatch 类用于测量时间,因为它比使用 DateTime 准确得多。

            您可以轻松地创建一个测试类来自动执行此操作。我已经发布了one such class in my blog。它可以比较两个 C# 代码片段/算法的性能。您所要做的就是重写 Method1 和 Method2 方法,将您要测试的代码片段放在那里,然后像这样使用测试类:

            Test test = new CustomTest();
            Console.WriteLine("\n==============================");
            Console.WriteLine(test.Execute());
            Console.WriteLine("==============================\n");
            

            【讨论】:

              【解决方案10】:

              您也可以使用 log4net,只需在要跟踪内容的地方添加 log.Info("Test"),您就会在 txt 文件中找到所有信息和该行执行的时间,例如:2018-12-13 10:02:16,704 [9] INFO Hms.Domain.Concrete.RoomsRepository [(null)] - Test Read更多信息在这里:https://www.infoworld.com/article/3120909/application-development/how-to-work-with-log4net-in-c.html

              【讨论】:

                猜你喜欢
                • 2020-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-03-03
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多