Aquí es una especie de resumen actualizado & actualizada de cuáles pueden ser las respuestas más útiles & comentarios en este tema + parámetros adicionales y variantes:
Primera cosa f Irst: Como otros han señalado en los comentarios, las cosas han cambiado en los últimos años y con el Windows "moderno" (Win XP ++) y .NET, y el hardware moderno no hay o hay pocas razones para no usar Stopwatch(). Ver MSDN para más detalles. Citas:?
"es la exactitud QPC afectados por los cambios de frecuencia del procesador causadas por la administración de energía o la tecnología Turbo Boost
No. Si el procesador tiene un TSC invariante, el QPC no se ve afectada por este tipo Si el procesador no tiene un TSC invariable, QPC revertirá a un temporizador de hardware de plataforma que no se verá afectado por los cambios de frecuencia del procesador o la tecnología Turbo Boost.
¿QPC funciona de manera confiable en sistemas multiprocesador? , sistema multi-core y sistemas con hiper-threading?
Sí
¿Cómo puedo determinar y validar que QPC funciona en mi máquina?
No necesita realizar tales comprobaciones.
¿Qué procesadores tienen TSC no invariables? [..Read más ..] "
Pero si usted no necesita la precisión de cronómetro() o al menos quiere saber exactamente sobre el rendimiento de cronómetro (estática vs instancia-based) y otras variantes posibles, continúe leyendo:
Tomé el punto de referencia anterior de cskwg, y extendí el código para más variantes. He medido con algunos años i7 4700 MQ y C# 7 con VS 2017 (para ser más preciso, compilado con .NET 4.5.2, a pesar de los literales binarios, es C# 6 (usado de esto: literales de cadena y 'usando estático'). Especialmente el rendimiento de Cronómetro() parece mejorar en comparación con el punto de referencia mencionado.
Este es un ejemplo de los resultados de 10 millones de repeticiones en un bucle, como siempre, los valores absolutos no son importantes, pero incluso los valores relativos pueden diferir en otro hardware:
32 bits, modo de lanzamiento sin optimización :
medidos: GetTickCount64() [ms]: 275
medido: Environment.TickCount [ms]: 45
medidos: DateTime.UtcNow.Ticks [ms]:
medidos: Cronómetro: .ElapsedTicks [ms]: 277
medidos: Cronómetro: .ElapsedMilliseconds [ms]: 548
medidos: estáticos Stopwatch.GetTimestamp [ms]: 193
Medido: Cronómetro + conversión a DateTime [ms ]: 551
compararlo con DateTime.Now.Ticks [ms]:
32 bits, de modo de liberación, optimizadas:
medidos: GetTickCount64() [ms]: 198
Medido: Environment.TickCount [ms]: 39
medidos: DateTime.UtcNow.Ticks [ms]: 66
medido (!): Cronómetro: .ElapsedTicks [ms]: 175
medidos: Cronómetro: .ElapsedMilliseconds [ms]:
medidos: estáticos Stopwatch.GetTimestamp [ms]: 175
medido: Cronómetro + de conversión a DateTime [ms]:
Com pare que con DateTime.Now.Ticks [ms]:
64 bit, modo de lanzamiento sin optimización:
medidos: GetTickCount64() [ms]: 205
Medido : Environment.TickCount [ms]: 39
medidos: DateTime.UtcNow.Ticks [ms]:
medidos: Cronómetro: .ElapsedTicks [ms]: 209
medidos: Cronómetro: .ElapsedMilliseconds [ms]: 285
medidos: estáticos Stopwatch.GetTimestamp [ms]: 187
Medido: Cronómetro + conversión a DateTime [ms]: 319
compararlo con DateTime.Now.Ticks [ms]: 3040
64 bits, de modo de liberación, optimizado:
medido: GetTickCount64() [ms]: 148
Medido: Medio Ambiente.TickCount [ms]: 31 (¿es todavía vale la pena?)
medidos: DateTime.UtcNow.Ticks [ms]: 76
medidos (!): Cronómetro: .ElapsedTicks [ms]: 178
medido: Cronómetro: .ElapsedMilliseconds [ms]: 226
medido: estáticos Stopwatch.GetTimestamp [ms]: 175
medido: Cronómetro + de conversión a DateTime [ms]: 246
compararlo con DateTime.Now.Ticks [ms ]: 3020
Puede ser muy interesante que creando un valor de DateTime para imprimir el tiempo del cronómetro no tenga casi ningún costo. Interesante en una forma más académica que práctica es que el cronómetro estático es ligeramente más rápido (como se esperaba). Algunos puntos de optimización son bastante interesantes. Por ejemplo, no puedo explicar por qué Stopwatch.ElapsedMilliseconds solo con 32 bits es tan lento en comparación con sus otras variantes, por ejemplo, la estática. Esto y DateTime.Now más del doble de su velocidad con 64 bit.
Puedes ver: solo para millones de ejecuciones, el tiempo de Stopwatch comienza a importar. Si este es realmente el caso (pero tenga cuidado micro-optimizando demasiado pronto), puede ser interesante que con GetTickCount64(), pero especialmente con DateTime.UtcNow, usted tiene un temporizador de 64 bits (largo) con menos precisión que Cronómetro, pero más rápido, para que no tenga que meterse con el entorno "feo" de 32 bits. TickCount.
Como era de esperar, DateTime.Now es de lejos el más lento de todos.
Si lo ejecuta, el código recupera también su precisión actual del cronómetro y más.
Este es el código de referencia completo:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using static System.Environment;
[...]
[DllImport("kernel32.dll") ]
public static extern UInt64 GetTickCount64(); // Retrieves a 64bit value containing ticks since system start
static void Main(string[] args)
{
const int max = 10_000_000;
const int n = 3;
Stopwatch sw;
// Following Process&Thread lines according to tips by Thomas Maierhofer: https://codeproject.com/KB/testing/stopwatch-measure-precise.aspx
// But this somewhat contradicts to assertions by MS in: https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396#Does_QPC_reliably_work_on_multi-processor_systems__multi-core_system__and_________systems_with_hyper-threading
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1); // Use only the first core
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Thread.Sleep(2); // warmup
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; // only int capacity, enough for a bit more than 24 days
}
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; // just init
sw = new Stopwatch();
sw.Start();
for (int i = 0; i < max; i++)
{
var a = new DateTime(sw.Elapsed.Ticks); // using variable dt here seems to make nearly no difference
}
sw.Stop();
//Console.WriteLine($"Measured: Stopwatch+conversion to DateTime [s] with millisecs: {dt:s.fff}");
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) ; // microsecond resolution: 1 million ticks per sec
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); // tickCount means millisec -> there are 10.000 milliseconds in 100 nanoseconds, which is the tick resolution in .NET, e.g. used for TimeSpan
Console.WriteLine($"- Approximated capacity (maxtime) of TickCount [dd:hh:mm:ss] {maxTimeForTickCountInteger:dd:HH:mm:ss}");
// this conversion from seems not really accurate, it will be between 24-25 days.
Console.WriteLine($"{NewLine}Done.");
while (Console.KeyAvailable)
Console.ReadKey(false);
Console.ReadKey();
}
Como no relacionada a un lado, si usted hace uso de DateTime para los cálculos matemáticos relacionados con la fecha, utilice siempre DateTime. UtcNow como DateTime.Now es susceptible al horario de verano ... tus cálculos podrían estar fuera por una hora, o peor, números negativos. –
@Scott: Pensé que vale la pena mencionar: incluso con 'UtcNow', está el problema de las sincronizaciones programadas de NTP: no es raro que el tiempo del sistema cambie en un orden de 10 segundos después de estas actualizaciones (en mi PC). – Groo
La matemática en realidad no es tan complicada ... 'int duration = unchecked ((int) ((uint) Environment.TickCount - (uint) start));' ... le dará la respuesta correcta independientemente de los refinanciamientos. (Lo ideal es saltear el elenco para regresar a 'int' a menos que lo necesite). – AnorZaken