以下是此线程中最有用的答案和注释以及其他基准和变体的更新和刷新的摘要:
首先要注意的是:正如其他人在评论中指出的那样,最近几年发生了变化,使用“现代” Windows(Win XP ++)和.NET,以及现代硬件,没有或几乎没有理由不使用Stopwatch()。有关详细信息,请参见MSDN。报价单:
“ QPC精度是否受电源管理或Turbo Boost技术引起的处理器频率变化的影响?
否。如果处理器的TSC不变,,则QPC不受这些变化的影响。如果处理器的TSC不变, QPC将恢复为平台硬件计时器,不受处理器频率变化或Turbo Boost技术的影响。
QPC是否可以在多处理器系统,多核系统以及具有超线程的系统上可靠地工作?
是
如何确定并验证QPC在我的计算机上可以正常工作?
您无需执行此类检查。
哪些处理器具有不变的TSC?[..进一步阅读..]“
但是,如果您不需要Stopwatch()的精度,或者至少想要确切了解Stopwatch的性能(静态与基于实例)以及其他可能的变体,请继续阅读:
我从cskwg手中接管了上述基准测试,并扩展了代码以使用更多变体。我已经在VS 2017上使用过几年的i7 4700 MQ和C#7进行了测量(更精确地说,是使用.NET 4.5.2编译的,尽管使用了二进制文字,但它还是C#6(用于:字符串文字和“使用静态')。与上述基准相比,特别是Stopwatch()的性能似乎有所提高。
这是一个循环中进行一千万次重复的结果的示例,一如既往,绝对值并不重要,但是即使相对值在其他硬件上也可能有所不同:
32位,发布模式,无优化:
测量值:GetTickCount64()[ms]:275
测量值:Environment.TickCount [ms]:45
测量值:DateTime.UtcNow.Ticks [ms]:167
测量值:秒表:.ElapsedTicks [ms]:277
测量值:秒表:.ElapsedMilliseconds [ ms]:548
测量:静态Stopwatch.GetTimestamp [ms]:193
测量:秒表+转换为DateTime [ms]:551
与DateTime.Now.Ticks比较[ms]:9010
32位,发布模式,已优化:
测量值:GetTickCount64()[ms]:198
测量值:Environment.TickCount [ms]:39
测量值:DateTime.UtcNow.Ticks [ms]:66 (!)
测量值:秒表:.ElapsedTicks [ms]:175
测量值:秒表: .ElapsedMilliseconds [ms]:491
测量:静态Stopwatch.GetTimestamp [ms]:175
测量:Stopwatch +转换为DateTime [ms]: 510
与DateTime.Now.Ticks比较[ms]:8460
64位,发布模式,未经优化:
测量值:GetTickCount64()[ms]:205
测量值:Environment.TickCount [ms]:39
测量值:DateTime.UtcNow.Ticks [ms]:127
测量值:秒表:.ElapsedTicks [ms]:209
测量值:秒表:.ElapsedMilliseconds [ ms]:285
测量:静态Stopwatch.GetTimestamp [ms]:187
测量:秒表+转换为DateTime [ms]:319
与DateTime.Now.Ticks比较[ms]:3040
64位,发布模式,已优化:
测量值:GetTickCount64()[ms]:148
测量值:Environment.TickCount [ms]:31 (是否仍然值得?)
测量值:DateTime.UtcNow.Ticks [ms]:76 (!)
测量值:秒表:.ElapsedTicks [ ms]:178
测量:秒表:.ElapsedMilliseconds [ms]:226
测量:静态Stopwatch.GetTimestamp [ms]:175
测量:秒表+转换为DateTime [ms]:246
与DateTime.Now.Ticks [ms]进行比较: 3020
可能很有趣的是,创建DateTime值以打印出秒表时间似乎几乎没有任何花费。与实际相比,更具学术性的有趣之处在于静态秒表的速度稍快(如预期)。一些优化点非常有趣。例如,我无法解释为什么只有32位的Stopwatch.ElapsedMilliseconds与其其他变体(例如静态变体)相比如此慢。这和DateTime.Now现在的速度是64位的两倍多。
您会看到:仅对于数百万次执行,秒表的时间开始变得重要。如果确实是这种情况(但要提防微优化为时过早),那么使用GetTickCount64()(尤其是使用DateTime.UtcNow)可能会很有趣,您有一个64位(长)的计时器,精度比秒表低,但速度更快,这样您就不必弄乱32位的“丑陋” Environment.TickCount。
不出所料,DateTime.Now是迄今为止最慢的。
如果您运行它,代码还将检索您当前的秒表精度以及更多信息。
这是完整的基准代码:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using static System.Environment;
[...]
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64();
static void Main(string[] args)
{
const int max = 10_000_000;
const int n = 3;
Stopwatch sw;
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Thread.Sleep(2);
Console.WriteLine($"Repeating measurement {n} times in loop of {max:N0}:{NewLine}");
for (int j = 0; j < n; j++)
{
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = GetTickCount64();
}
sw.Stop();
Console.WriteLine($"Measured: GetTickCount64() [ms]: {sw.ElapsedMilliseconds}");
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var tickCount = Environment.TickCount;
}
sw.Stop();
Console.WriteLine($"Measured: Environment.TickCount [ms]: {sw.ElapsedMilliseconds}");
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = DateTime.UtcNow.Ticks;
}
sw.Stop();
Console.WriteLine($"Measured: DateTime.UtcNow.Ticks [ms]: {sw.ElapsedMilliseconds}");
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = sw.ElapsedMilliseconds;
}
sw.Stop();
Console.WriteLine($"Measured: Stopwatch: .ElapsedMilliseconds [ms]: {sw.ElapsedMilliseconds}");
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = Stopwatch.GetTimestamp();
}
sw.Stop();
Console.WriteLine($"Measured: static Stopwatch.GetTimestamp [ms]: {sw.ElapsedMilliseconds}");
DateTime dt=DateTime.MinValue;
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = new DateTime(sw.Elapsed.Ticks);
}
sw.Stop();
Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [ms]: {sw.ElapsedMilliseconds}");
Console.WriteLine();
}
sw = new Stopwatch();
var tickCounterStart = Environment.TickCount;
sw.Start();
for (int i = 0; i < max/10; i++)
{
var a = DateTime.Now.Ticks;
}
sw.Stop();
var tickCounter = Environment.TickCount - tickCounterStart;
Console.WriteLine($"Compare that with DateTime.Now.Ticks [ms]: {sw.ElapsedMilliseconds*10}");
Console.WriteLine($"{NewLine}General Stopwatch information:");
if (Stopwatch.IsHighResolution)
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
else
Console.WriteLine("- Using high-resolution performance counter for Stopwatch class.");
double freq = (double)Stopwatch.Frequency;
double ticksPerMicroSec = freq / (1000d*1000d) ;
Console.WriteLine($"- Stopwatch accuracy- ticks per microsecond (1000 ms): {ticksPerMicroSec:N1}");
Console.WriteLine(" (Max. tick resolution normally is 100 nanoseconds, this is 10 ticks/microsecond.)");
DateTime maxTimeForTickCountInteger= new DateTime(Int32.MaxValue*10_000L);
Console.WriteLine($"- Approximated capacity (maxtime) of TickCount [dd:hh:mm:ss] {maxTimeForTickCountInteger:dd:HH:mm:ss}");
Console.WriteLine($"{NewLine}Done.");
while (Console.KeyAvailable)
Console.ReadKey(false);
Console.ReadKey();
}