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

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

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
有帮助吗?

解决方案

不,这不对。使用 跑表 (在 System.Diagnostics)

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

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

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

值得一提的是 DateTime.Now 通常比 DateTime.UtcNow 由于必须处理时区的工作, 夏令时 等等。

DateTime.UtcNow 的分辨率通常为 15 毫秒。看 约翰·查普曼的博客文章 关于 DateTime.Now 精确的总结。

有趣的琐事:秒表又回到了 DateTime.UtcNow 如果您的硬件不支持高频计数器。您可以通过查看静态场来检查秒表是否使用硬件来实现高精度 秒表.Is高分辨率.

其他提示

如果你想要一些快速而肮脏的东西,我建议使用秒表来代替以获得更高的精度。

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

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

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

本文 说首先你需要比较三种选择, Stopwatch, DateTime.NowDateTime.UtcNow.

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

然而,事实证明,计数器几乎总是存在的 - 请参阅 关于高分辨率性能计数器及其与.NET Stopwatch相关的存在的解释?.

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

Enter image description here

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

一件事 Stopwatch 更好的是它提供更高分辨率的时间测量。另一个是它更加面向对象的性质。然而,创建一个 OO 包装器 UtcNow 不可能很难。

将基准测试代码推送到实用程序类/方法中非常有用。这 StopWatch 类不需要 Disposed 或者 Stopped 错误时。所以,最简单的代码 时间 一些 行动

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);
}

跑表 功能会更好(精度更高)。不过,我还建议您下载一种流行的分析器(点追踪蚂蚁 是我用过最多的...DotTrace 的免费试用版功能齐全,不会像其他一些软件那样烦人)。

使用 System.Diagnostics.Stopwatch 类。

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

// Do some code.

sw.Stop();

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

同上,秒表,它好多了。

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

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

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

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

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

这是关于它如何工作以及为什么工作的更完整的解释

@肖恩·钱伯斯

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

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 的设计器工具箱中找到它

这是正确的方法:

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);
    }
}

欲了解更多信息,请通过 使用秒表代替 DataTime 来获取准确的性能计数器.

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

Microsoft 的模式和实践小组在以下方面提供了一些指导 Visual Studio Team 系统性能测试指南.

我刚刚在万斯·莫里森的博客中找到了一篇关于 CodeTimer 类 他写道,这使得使用 StopWatch 更容易,并且可以做一些有趣的事情。

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

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

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

编辑:

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

这看起来是一篇好文章

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

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


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;

这还不够专业:

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 配置文件中轻松分隔不同的代码间隔。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top