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

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

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。花费的时间是(结束开始)/ Stopwatch。频率。

“最佳”是主观的。这个问题需要客观地定义“最佳”的含义。

#1 楼

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

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

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


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

值得一提的是DateTime.Now由于必须进行时区,DST等工作,因此通常比DateTime.UtcNow慢很多。

DateTime.UtcNow通常具有15毫秒的分辨率。请参见John Chapman的有关DateTime.Now精度的博客文章。

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

评论


我要放置一个PerformWork();在秒表“加热”之前。

– DiVan
11年6月23日在8:20

还必须添加建议,如果PerformWork()非常短,则可以重复调用它并计算一批调用的平均值。另外,请对整个通话进行计时,而不要启动/停止秒表,以免产生频闪效应,这种频闪效应会使您的计时测量变得混乱。

– devgeezer
2012年4月11日下午6:24

秒表在多核上不是线程安全的。请参阅stackoverflow.com/questions/6664538/…和stackoverflow.com/questions/1149485/…

– Pavel Savara
2012年7月26日,0:36

sw。经过的毫秒;也能

–Flappy
2014年5月6日11:09



@Pavel,很明显,Microsoft建议秒表是运行Windows 7和Windows 8的现代多核处理器上的最佳解决方案(低开销和高精度)。msdn.microsoft.com/zh-cn/library/windows/桌面/…

–罗恩
15年6月10日在18:04

#2 楼

如果您想要快速又脏的东西,我建议您改用秒表来提高精度。

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

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


或者,如果您需要更高级的功能,则可能应该考虑使用ANTS这样的第三方探查器。

#3 楼

本文说,首先,您需要比较StopwatchDateTime.NowDateTime.UtcNow这三种选择。

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

但是,事实证明,计数器几乎总是存在-请参见有关高分辨率性能计数器及其与.NET秒表的关系。

这是一个性能图。请注意,UtcNow与替代产品相比具有较低的性能成本:



X轴是示例数据大小,Y轴是示例的相对时间。 />
Stopwatch的一个优点是可以提供更高分辨率的时间测量。另一个是其更面向对象的性质。但是,围绕UtcNow创建OO包装器并不难。

评论


第一个链接似乎已断开。

– Peter Mortensen
13年3月22日在20:14

是坏了..时间机器可以显示它,我猜。顺便说一句,为什么您要编辑“三个”,我相信这里并不需要。

– Valentin Kuzub
13年3月22日在20:17

#4 楼

将基准测试代码放入实用程序类/方法中很有用。错误时,StopWatch类不必是DisposedStopped。因此,计时某个动作最简单的代码是

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


评论


更好的粒度呢?许多事情在不到一毫秒的时间内发生。

–亨里克
2011-2-18在7:32

然后返回Elapsed属性,它是一个TimeSpan。我只是向您展示模式。祝您实施愉快。

– Anthony Mastrean
2011-02-18 13:59

返回Elapsed.TotalMilliseconds以获得更高的精度。参见此问题stackoverflow.com/questions/8894425/…

– nawfal
13年4月12日在6:19

#5 楼

秒表功能会更好(精度更高)。不过,我也建议您下载其中一个最受欢迎的分析器(DotTrace和ANTS是我使用最多的分析器... DotTrace的免费试用版功能齐全,不像其他一些那样na)。

#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 楼

同上秒表,它会更好。

关于性能测量,您还应该检查“ //某些执行过程”是否是很短的过程。

请记住您的“ //某些执行过程”的第一次运行可能比随后的运行慢得多。

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

#8 楼

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

在线程中查找瓶颈的最直接方法是使其运行,并且在做任何让您等待的事情时,请使用暂停或中断键将其暂停。这样做几次。如果您的瓶颈花费了X%的时间,则X%是您在每个快照的动作中都将其捕获的概率。

这里更全面地说明了它如何工作以及为什么起作用

#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中作为控件公开。表单...您可以在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);
    }
}


有关更多信息,请通过使用秒表代替DataTime以获得准确的性能计数器。

#11 楼

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

Microsoft的“模式和实践”小组在Visual Studio Team System性能测试指南中提供了一些指南。

#12 楼

我刚刚在Vance Morrison的博客中找到有关他编写的CodeTimer类的文章,该类使使用StopWatch更容易,并且在侧面做了一些整洁的事情。

#13 楼

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

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


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;


#14 楼

这还不够专业:

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

#15 楼

我很少进行这种性能检查(我倾向于只是认为“这很慢,要使其更快”),所以我几乎总是这样做。
Google确实显示了很多资源/有关性能检查的文章。
很多人提到使用pinvoke获取性能信息。我学习的许多材料实际上只提到了使用perfmon。.
编辑:
看过StopWatch的话题。。不错!我学到了一些东西:)
这看起来像是一篇不错的文章

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

因此,总之,如果您不太关心精度,则DateTime.UtcNow是最快的。这也支持该问题的答案https://stackoverflow.com/a/6986472/637142。