DateTime.Now是衡量函数性能的最佳方式吗?

493

我需要找到瓶颈,并尽可能准确地测量时间。

以下代码片段是否是衡量性能的最佳方式?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

顺便说一下,如果您不想要快速而肮脏的东西,可以使用性能计数器。 - Jonathan C Dickinson
1
如果您需要更高的精度,请使用Stopwatch.GetTimestamp,否则答案是正确的。 - dbasnett
@dbasnett,您能否在回答中提供更多详细信息? - David Basarab
参见:反对使用DateTime.Now的理由 - Matt Johnson-Pint
2
“Best” 是主观的。这个问题需要以客观的方式定义“最好”的含义。 - Heretic Monkey
显示剩余2条评论
16个回答

6
< p > < em > Visual Studio Team System 具有一些功能,可以帮助解决这个问题。基本上,您可以编写单元测试并将它们混合在不同的方案中,以作为压力或负载测试的一部分运行对软件进行测试。这可能有助于识别影响应用程序性能最大的代码区域。

微软的模式和实践小组在Visual Studio Team System Performance Testing Guidance中提供了一些指导。


5
我在我的程序中使用的方法是使用StopWatch类,如下所示。
Stopwatch sw = new Stopwatch();
sw.Start();


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;

5

我刚在Vance Morrison的博客中发现了一篇关于CodeTimer类的文章。这个类可以让使用StopWatch更加容易,并且还有一些很棒的功能。


4

这篇文章不够专业:

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

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

一种更可靠的版本是:
PerformWork();

int repeat = 1000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
   PerformWork();
}

sw.Stop();

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

在我的实际代码中,我将添加GC.Collect调用来改变托管堆的状态,然后添加Sleep调用,以便在ETW profile中轻松地分隔不同的代码间隔。


4
我很少进行此类性能检查(我倾向于只是认为“这很慢,让它更快”),所以我基本上一直都这样做。
谷歌可以找到很多关于性能检查的资源/文章。
许多人提到使用pinvoke来获取性能信息。我学习的材料中很多只是提到使用perfmon。
编辑:
看到了StopWatch的讲话...不错!我学到了一些东西 :) 这篇文章看起来不错

-1

由于我并不太关注精度,因此最终将它们进行了比较。我正在捕获网络上的大量数据包,并希望在收到每个数据包时记录时间。这是测试 500 万次迭代的代码。

    int iterations = 5000000;

    // Test using datetime.now
    {
        var date = DateTime.UtcNow.AddHours(DateTime.UtcNow.Second);

        var now = DateTime.UtcNow;

        for (int i = 0; i < iterations; i++)
        {
            if (date == DateTime.Now)
                Console.WriteLine("it is!");
        }
        Console.WriteLine($"Done executing {iterations} iterations using datetime.now. It took {(DateTime.UtcNow - now).TotalSeconds} seconds");
    }

    // Test using datetime.utcnow
    {
        var date = DateTime.UtcNow.AddHours(DateTime.UtcNow.Second);

        var now = DateTime.UtcNow;

        for (int i = 0; i < iterations; i++)
        {
            if (date == DateTime.UtcNow)
                Console.WriteLine("it is!");
        }
        Console.WriteLine($"Done executing {iterations} iterations using datetime.utcnow. It took {(DateTime.UtcNow - now).TotalSeconds} seconds");
    }

    // Test using stopwatch
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();

        var now = DateTime.UtcNow;

        for (int i = 0; i < iterations; i++)
        {
            if (sw.ElapsedTicks == DateTime.Now.Ticks)
                Console.WriteLine("it is!");
        }
        Console.WriteLine($"Done executing {iterations} iterations using stopwatch. It took {(DateTime.UtcNow - now).TotalSeconds} seconds");
    }

输出结果为:

Done executing 5000000 iterations using datetime.now. It took 0.8685502 seconds 
Done executing 5000000 iterations using datetime.utcnow. It took 0.1074324 seconds 
Done executing 5000000 iterations using stopwatch. It took 0.9625021 seconds

因此总的来说,如果你不太关心精度,DateTime.UtcNow 是最快的。 这也支持这个问题的答案https://dev59.com/pnVD5IYBdhLWcg3wR5ko#6986472


这是一个很好的测试。不幸的是,在当前状态下它存在缺陷,使得它看起来像是Stopwatch执行所需的时间比实际上要多得多。在秒表测试中,您进行了额外的日期时间操作(sw.ElapsedTicks == DateTime.Now.Ticks),这不仅需要从系统时钟获取当前时间,而且在此之前还需要将日期时间对象转换为当前时区,因为您使用的是DateTime.Now而不是DateTime.UtcNow。因此,您实际上是在测试DateTime.Now + Stopwatch的执行时间,而不仅仅是Stopwatch本身。 - undefined
我投了反对票是为了提高对潜在错误信息的认识,但如果这个问题得到纠正,我很乐意改投赞成票。为了使测试更加准确,你应该在循环之前存储DateTime.(Utc)Now.Ticks的值,这样在我的机器上,以及在.NET 6和.NET Fiddle上运行时,Stopwatch才是最快的。链接:https://dotnetfiddle.net/dSg3bN - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接