c# - startnew - System.Diagnostics.Stopwatch devuelve números negativos en las propiedades de Elapsed...
stopwatch() (4)
Descompilé la clase Cronómetro en .NET 2.0 y .NET 4.0 usando Reflector y luego comparé las diferencias para ver cómo se solucionó. Además de la adición del nuevo método de reinicio, esto es todo lo que encontré para una diferencia:
public void Stop()
{
if (this.isRunning)
{
long num2 = GetTimestamp() - this.startTimeStamp;
this.elapsed += num2;
this.isRunning = false;
// THE NEXT 4 LINES ARE NEW IN .NET 4.0:
if (this.elapsed < 0L)
{
this.elapsed = 0L;
}
}
}
Así que, básicamente, establecieron el tiempo transcurrido en 0 en el método Stop si el valor es negativo. Todavía hay errores IMHO:
- ¿Qué sucede si el usuario lee alguna de las propiedades transcurridas antes de detener el cronómetro? Es posible que todavía obtenga un valor negativo.
- Restablecer a 0 no es correcto. Debía haber transcurrido algún tiempo, ¡incluso si solo eran unos pocos microsegundos!
- No hace nada para manejar los valores positivos transcurridos inusualmente grandes que yo y otros hemos informado.
EDIT: Desafortunadamente, # 2 y # 3 están más allá del poder de .NET Framework:
Aquí está el núcleo del problema: de MSDN en QueryPerformanceCounter que es la API utilizada por la clase Stopwatch:
En una computadora multiprocesador, no debería importar a qué procesador se llama. Sin embargo, puede obtener diferentes resultados en diferentes procesadores debido a errores en el sistema básico de entrada / salida (BIOS) o la capa de abstracción de hardware (HAL). Para especificar la afinidad del procesador para un hilo, use la función SetThreadAffinityMask.
No solo utilice el cronómetro .NET 4.0 y suponga que el problema está solucionado. No lo es y no pueden hacer nada al respecto a menos que quieras que se deshagan de tu afinidad con el hilo. De la documentación de la clase Cronómetro:
En una computadora multiprocesador, no importa en qué procesador se ejecuta el subproceso. Sin embargo, debido a errores en el BIOS o en la Capa de abstracción de hardware (HAL), puede obtener diferentes resultados de tiempo en diferentes procesadores. Para especificar la afinidad del procesador para un hilo, utilice el método ProcessThread.ProcessorAffinity.
¿Es un comportamiento normal que el Cronómetro pueda devolver valores negativos? Código de ejemplo a continuación se puede utilizar para reproducirlo.
while (true)
{
Stopwatch sw = new Stopwatch();
sw.Start();
sw.Stop();
if (sw.ElapsedMilliseconds < 0)
Debugger.Break();
}
El único lugar donde puedo reproducir números negativos es mi máquina virtual (alojada por Hyper-V en una máquina de 8 núcleos)
Esto es un bug . Parece que no tiene mucha atención a su alrededor, por lo que sugiero seguir con ese informe.
La solución alternativa no inspiradora parece ser ignorar los valores negativos:
long elapsedMilliseconds = Math.Max(0, stopwatch.ElapsedMilliseconds);
La única solución que he encontrado para obtener el tiempo transcurrido correcto en una VM es (VB):
Dim tstart AS DateTime = Now
...executing code...
Dim telapsed = (Now - tstart).TotalMilliseconds
La resolución "Cerrado como arreglado" en el error de Microsoft Connect debe significar que se corrigió en .NET 4. He ejecutado el código de reproducción en mi escritorio y en una VM durante varios minutos y no obtuve valores negativos.