计算方法的执行时间

Calculate the execution time of a method

提问人:Mahdi Tahsildari 提问时间:12/24/2012 最后编辑:CommunityMahdi Tahsildari 更新时间:4/17/2023 访问量:688944

问:

可能的重复:
如何测量函数的运行时间?

我有一个 I/O 耗时方法,可以将数据从一个位置复制到另一个位置。计算执行时间的最佳和最真实的方法是什么???????还有其他解决方案吗?我想要最准确的,尽可能简短。ThreadTimerStopwatch

C# .NET 计时器 IO 秒表

评论


答:

1444赞 Darin Dimitrov 12/24/2012 #1

秒表是为此目的而设计的,是在 .NET 中测量时间执行的最佳方法之一。

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

不要使用 DateTime 来度量 .NET 中的时间执行。


更新:

正如 @series0ne 在评论部分所指出的那样:如果你想真正精确地测量某些代码的执行,你将不得不使用操作系统中内置的性能计数器。以下答案包含一个很好的概述。

评论

2赞 Mahdi Tahsildari 12/24/2012
没错,这个案例呢:我有一个内部的 foreach 循环,但秒表在完成所有工作之前就停止了。ThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); });
17赞 Matthew Layton 12/24/2012
@DarinDimitrov - 秒表不完全准确?请记住,.NET 背景噪音(如 JITing)会导致不同的执行时间发生。因此,实际上,为了进行准确的测量,OP应该使用性能分析器。
3赞 Darin Dimitrov 12/24/2012
@series0ne,非常好的观点。我将更新我的答案,以包括您的宝贵意见。
8赞 Matthew Layton 10/27/2013
@DarinDimitrov,我最近采访了一位非常熟练的高级开发人员。他向我指出,使用 DateTimes 实际上比使用 StopWatch 更准确。他说,这样做的原因是 .NET 中的 Stopwatch 没有考虑 CPU 亲和力,因此,如果你的线程从一个内核移动到另一个内核,StopWatch 不会考虑其他内核的执行时间;只有线程开始执行的那个。您对此有何看法?
2赞 Darin Dimitrov 10/28/2013
@series0ne,高级开发人员告诉您的有关秒表和 DateTime 的内容绝对是真的。除了使用 DateTime 时,您没有足够的准确性。问题在于,.NET 中没有这样的类可以允许您使用所有这些功能。
21赞 Jeff Foster 12/24/2012 #2

如果您有兴趣了解性能,最好的答案是使用探查器。

否则,System.Diagnostics.StopWatch 将提供高分辨率计时器。

评论

0赞 Matthew Layton 12/24/2012
绝对正确!我有点沮丧,这里有这么多人建议使用秒表,因为它并不完全准确。但是,正如您建议使用性能分析器一样,这是正确的方法!+1
41赞 Soner Gönül 12/24/2012 #3

StopWatch 类寻找您的最佳解决方案。

Stopwatch sw = Stopwatch.StartNew();
DoSomeWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

此外,它还有一个名为 Stopwatch.IsHighResolution 的静态字段。当然,这是硬件和操作系统的问题。

指示计时器是否基于高分辨率性能 计数器。

7赞 Brian Agnew 12/24/2012 #4

StopWatch 将使用高分辨率计数器

秒表通过计算计时器滴答声来测量经过的时间 底层计时器机制。如果已安装硬件并运行 系统支持高分辨率性能计数器,然后 秒表类使用该计数器来测量经过的时间。否则 Stopwatch 类使用系统计时器来测量经过的时间。用 用于确定精度的 Frequency 和 IsHighResolution 字段 以及秒表计时实现的分辨率。

如果你正在测量 IO,那么你的数据可能会受到外部事件的影响,我会非常担心。精确性(如上所述)。相反,我会进行一系列测量,并考虑这些数字的平均值和分布。

94赞 Matthew Layton 12/24/2012 #5

根据个人经验,该类可用于测量方法的执行时间,但是,请注意:它并不完全准确!System.Diagnostics.Stopwatch

请看以下示例:

Stopwatch sw;

for(int index = 0; index < 10; index++)
{
    sw = Stopwatch.StartNew();
    DoSomething();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

sw.Stop();

示例结果

132ms
4ms
3ms
3ms
2ms
3ms
34ms
2ms
1ms
1ms

现在你想知道;“那么,为什么第一次花了 132 毫秒,而其余时间却少得多?”

答案是,它不能补偿 .NET 中的“背景噪音”活动,例如 JITing。因此,首次运行方法时,首先使用 .NET JIT。执行此操作所需的时间将添加到执行时间中。同样,其他因素也会导致执行时间不同。Stopwatch

您真正应该寻找绝对准确性的是性能分析

请看以下内容:

RedGate ANTS Performance Profiler 是一种商业产品,但会产生非常准确的结果。- 通过 .NET 分析提高应用程序的性能

这是一篇关于分析的 StackOverflow 文章: - 有哪些好的 .NET 分析器?

我还写了一篇关于使用 Stopwatch 进行性能分析的文章,您可能想看看 - .NET 中的性能分析

评论

66赞 Eric Lippert 12/24/2012
我不确定为什么这是一个不准确的例子。秒表准确地测量了第一次通话的总成本,这肯定是与将要运行此代码的客户相关的。他们不在乎这 132 毫秒是计入方法执行还是抖动,他们关心的是经过的总时间。
1赞 Matthew Layton 12/24/2012
@EricLippert你在这里提出了一个好的观点,诚然,如果代码只运行一次,那么是的,JITing 和其他各种“噪音”将可信地影响结果,但是 OP(以及其他)可能有其他场景,例如,代码可能在循环中执行,因此您可以计算所有迭代的平均值, 或需要最长/最短的执行时间。
2赞 svick 12/26/2012
@series0ne 如果您关心循环的性能,那么请测量循环的性能。不要简单地假设做 n 次某事意味着它会比执行一次慢 n 倍。
4赞 ILIA BROUDNO 2/10/2018
首先,代码示例应生成数量不断增加的输出,因为 StopWatch 永远不会在循环中重置。我所说的“应该”是指它确实如此(我检查过)。因此,您的输出与代码不匹配。其次,当我更正代码以在循环中执行停止/写入/重置/启动时,第一次测量与其他测量相同。我的猜测是你的 DoSomething 在第一次运行时会做更长时间的事情。JIT 可能是也可能不是原因,但并不是秒表影响了测量。因此 -1。
3赞 Rui Miguel Pinheiro 10/6/2018
ILIA BROUDNO 是绝对正确的,我得到了相同的结果。@series0ne,循环中有一个 Console.WriteLine,到目前为止写入 ms;因为你只在循环结束后停止手表,所以每次迭代都会随着时间的推移而增加,所以我们应该看到类似 3、6、10、12、15 的东西......随着时间在执行过程中累积。
2赞 Md.Rakibuz Sultan 2/14/2019 #6
 using System.Diagnostics;
 class Program
 {
    static void Test1()
    {
        for (int i = 1; i <= 100; i++)
        {
            Console.WriteLine("Test1 " + i);
        }
    }
  static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        Test1();
        sw.Stop();
        Console.WriteLine("Time Taken-->{0}",sw.ElapsedMilliseconds);
   }
 }
13赞 Tạ Lục Gia Hoàng 6/18/2020 #7

遵循此 Microsoft 文档

using System;
using System.Diagnostics;
using System.Threading;
class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        Thread.Sleep(10000);
        stopWatch.Stop();
        // Get the elapsed time as a TimeSpan value.
        TimeSpan ts = stopWatch.Elapsed;

        // Format and display the TimeSpan value.
        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds,
            ts.Milliseconds / 10);
        Console.WriteLine("RunTime " + elapsedTime);
    }
}

输出:RunTime 00:00:09.94

7赞 Khai Vu 8/31/2021 #8

您还可以使用此功能,“获取自系统启动以来经过的毫秒数”。

System.Environment.TickCount

例如

static void method1()
{
    for (int i = 1; i <= 100; i++)
    {
        Console.WriteLine("Test1 " + i);
    }
}
static void Main(string[] args)
{
    var startTime = Environment.TickCount;
    method1();
    var endTime = Environment.TickCount;
    Console.WriteLine("RunTime " + (endTime - startTime));
}