DateTime.Now 是衡量函数性能的最佳方法吗? [关闭]

Posted

技术标签:

【中文标题】DateTime.Now 是衡量函数性能的最佳方法吗? [关闭]【英文标题】:Is DateTime.Now the best way to measure a function's performance? [closed] 【发布时间】:2010-09-06 22:00:57 【问题描述】:

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

下面的代码 sn -p 是衡量性能的最佳方法吗?

DateTime startTime = DateTime.Now;

// Some execution process

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

【问题讨论】:

顺便说一句,如果您不是在寻找快速而肮脏的性能计数器,可以使用。 如果您需要更高的精度,请使用 Stopwatch.GetTimestamp,否则答案是好的。 @dbasnett 你能详细回答一下吗? 在上面的示例中,将 start 和 endtime 更改为 long 并将 Stopwatch.GetTimestamp 分配给它们而不是 DateTime.Now。所用时间为(end-start)/Stopwatch.Frequency。 “最佳”是主观的。这个问题需要客观地定义什么是“最好”。 【参考方案1】:

不,不是。使用Stopwatch(在System.Diagnostics

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

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

秒表自动检查是否存在高精度计时器。

值得一提的是,DateTime.Now 通常比DateTime.UtcNow 慢很多,因为需要处理时区、DST 等。

DateTime.UtcNow 通常具有 15 毫秒的分辨率。请参阅John Chapman's blog post 关于DateTime.Nowprecision 以获得精彩的总结。

有趣的琐事:如果您的硬件不支持高频计数器,秒表会退回到DateTime.UtcNow。您可以通过查看静态字段Stopwatch.IsHighResolution 来检查 Stopwatch 是否使用硬件来实现高精度。

【讨论】:

我会放置一个 PerformWork();在秒表之前“加热”。 还必须添加建议,如果您的PerformWork() 很短,您可以重复调用它并计算这批调用的平均值。此外,为整批呼叫计时,而不是开始/停止您的 Stopwatch,以避免频闪效应混淆您的计时测量。 秒表在多核上不是线程安全的。见***.com/questions/6664538/… 和***.com/questions/1149485/… sw.ElapsedMilliseconds;还可以 @Pavel,明确地说,Stopwatch 被 Microsoft 推荐为运行 Windows 7 和 Windows 8 的现代多核处理器上的最佳解决方案(低开销和高精度)。msdn.microsoft.com/en-us/library/windows/desktop/…【参考方案2】:

如果您想要快速而肮脏的东西,我建议您使用秒表来获得更高的精确度。

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: 0", sw.Elapsed.TotalMilliseconds);

或者,如果您需要更复杂的东西,您可能应该考虑使用第 3 方分析器,例如 ANTS。

【讨论】:

【参考方案3】:

This article 表示首先您需要比较三个备选方案,StopwatchDateTime.NowDateTime.UtcNow

它还表明在某些情况下(当性能计数器不存在时)秒表正在使用 DateTime.UtcNow + 一些额外的处理。因此很明显,在这种情况下 DateTime.UtcNow 是最好的选择(因为其他人使用它+一些处理)

然而,事实证明,计数器几乎总是存在 - 请参阅 Explanation about high-resolution performance counter and its existence related to .NET Stopwatch?

这是一个性能图表。请注意 UtcNow 与替代方案相比的性能成本有多低:

X轴是样本数据大小,Y轴是例子的相对时间。

Stopwatch 更擅长的一件事是它提供了更高分辨率的时间测量。另一个是它更多的面向对象性质。但是,围绕 UtcNow 创建一个 OO 包装器并不难。

【讨论】:

第一个链接好像坏了。 变得坏了是的..时间机器可以显示它我猜。顺便说一句,为什么要编辑“三个”,我相信这里不需要。【参考方案4】:

将您的基准测试代码推送到实用程序类/方法中很有用。 StopWatch 类不需要是 DisposedStopped 错误。因此,time 一些 action 的最简单代码是

public partial class With

    public static long Benchmark(Action action)
    
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    

示例调用代码

public void Execute(Action action)

    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in 0 ms.”, time);

这里是扩展方法版本

public static class Extensions

    public static long Benchmark(this Action action)
    
        return With.Benchmark(action);
    

以及示例调用代码

public void Execute(Action action)

    var time = action.Benchmark()
    log.DebugFormat(“Did action in 0 ms.”, time);

【讨论】:

更好的粒度呢?许多事情在不到一毫秒的时间内发生。 然后返回 Elapsed 属性,它是一个 TimeSpan。我只是向你展示模式。玩得开心。 返回 Elapsed.TotalMilliseconds 以获得更高的精度。也看到这个问题***.com/questions/8894425/…【参考方案5】:

stopwatch 功能会更好(精度更高)。我还建议只下载一个流行的分析器,不过(DotTrace 和 ANTS 是我用得最多的... DotTrace 的免费试用版功能齐全,不会像某些其他人)。

【讨论】:

【参考方案6】:

使用 System.Diagnostics.Stopwatch 类。

Stopwatch sw = new Stopwatch();
sw.Start();

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

【讨论】:

【参考方案7】:

同上秒表,更好。

关于性能测量,您还应该检查您的“// Some Execution Process”是否是一个非常短的过程。

还请记住,“// Some Execution Process”的第一次运行可能比后续运行慢很多。

我通常通过在循环中运行 1000 次或 1000000 次来测试一个方法,我得到的数据比运行一次要准确得多。

【讨论】:

【参考方案8】:

这些都是衡量时间的好方法,但这只是寻找瓶颈的一种非常间接的方法。

在线程中找到瓶颈的最直接方法是让它运行,当它在做任何让你等待的事情时,用暂停或中断键停止它。这样做几次。如果您的瓶颈需要 X% 的时间,则 X% 是您在每个快照的行为中捕获它的概率。

Here's a more complete explanation of how and why it works

【讨论】:

【参考方案9】:

@Sean Chambers

仅供参考,.NET Timer 类不用于诊断,它以预设的时间间隔生成事件,如下所示(来自MSDN):

System.Timers.Timer aTimer;
public static void Main()

    // Create a timer with a ten second interval.
    aTimer = new System.Timers.Timer(10000);

    // Hook up the Elapsed event for the timer.
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    // Set the Interval to 2 seconds (2000 milliseconds).
    aTimer.Interval = 2000;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program.");
    Console.ReadLine();


// Specify what you want to happen when the Elapsed event is 
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)

    Console.WriteLine("The Elapsed event was raised at 0", e.SignalTime);

所以这真的不能帮助你知道某件事花了多长时间,只是已经过去了一定的时间。

计时器也在 System.Windows.Forms 中作为控件公开...您可以在 VS05/VS08 的设计器工具箱中找到它

【讨论】:

【参考方案10】:

这是正确的方法:

using System;
using System.Diagnostics;

class Program

    public static void Main()
    
        Stopwatch stopWatch = Stopwatch.StartNew();

            // some other code

        stopWatch.Stop();

        // this not correct to get full timer resolution
        Console.WriteLine("0 ms", stopWatch.ElapsedMilliseconds);

        // Correct way to get accurate high precision timing
        Console.WriteLine("0 ms", stopWatch.Elapsed.TotalMilliseconds);
    

更多信息请通过Use Stopwatch instead of DataTime for getting accurate performance counter

【讨论】:

【参考方案11】:

Visual Studio Team System 有一些功能可以帮助解决这个问题。本质上,您可以编写单元测试并将它们混合在不同的场景中,以作为压力或负载测试的一部分针对您的软件运行。这可能有助于确定对您的应用程序性能影响最大的代码区域。

Microsoft 的模式和实践小组在 Visual Studio Team System Performance Testing Guidance 中有一些指导。

【讨论】:

【参考方案12】:

我刚刚在 Vance Morrison 的博客中发现了一篇关于 a CodeTimer class 的帖子,他写道,这使得使用 StopWatch 变得更加容易,并且还做了一些简洁的事情。

【讨论】:

【参考方案13】:

我在我的程序中使用的方式是使用 StopWatch 类,如此处所示。

Stopwatch sw = new Stopwatch();
sw.Start();


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;

【讨论】:

【参考方案14】:

我很少做这种性能检查(我倾向于认为“这很慢,让它更快”)所以我几乎总是这样做。

谷歌确实揭示了很多用于性能检查的资源/文章。

很多人提到使用 pinvoke 来获取性能信息。我研究的很多材料只真正提到了使用 perfmon..

编辑:

看过 StopWatch 的演讲.. 不错!我学到了一些东西:)

This looks like a good article

【讨论】:

【参考方案15】:

这还不够专业:

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

Console.WriteLine("Time taken: 0ms", 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: 0ms", sw.Elapsed.TotalMilliseconds / repeat);

在我的真实代码中,我将添加 GC.Collect 调用以将托管堆更改为已知状态,并添加 Sleep 调用以便在 ETW 配置文件中轻松分离不同的代码间隔。

【讨论】:

【参考方案16】:

由于我不太关心精度,所以我最终将它们进行了比较。我在网络上捕获了很多数据包,我想确定接收每个数据包的时间。这是测试 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://***.com/a/6986472/637142。

【讨论】:

以上是关于DateTime.Now 是衡量函数性能的最佳方法吗? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

性能测试的精确时间测量[重复]

datetime如何判断是否周末?

datetime.now()提示没有now方法

为啥 DateTime.Now 是属性而不是方法?

python时间处理函数

衡量 iOS 应用性能的策略