2012-01-24 22 views
5

Al usar Stopwatch.GetTimestamp() encontramos que si registra el valor de retorno y luego continúa llamándolo y comparándolo con el valor de retorno anterior, eventualmente pero impredeciblemente devolverá un valor menor que el original.¿Cuesta cronometrar Stopwatch.Getttamptamp? O retroceder?

¿Este comportamiento es esperado?

El propósito de hacer esto en el código de producción es tener un tiempo de sistema preciso de microsegundos.

La técnica implica llamar a DateTime.UtcNow y también llamar a Stopwatch.GetTimestamp() como originalUtcNow y originalTimestamp, respectivamente.

A partir de ese momento, la aplicación simplemente llama a Stopwatch.GetTimestamp() y utiliza Stopwatch.Frequency calcula la diferencia con la variable originalTimestamp y luego agrega esa diferencia a laUtcNow original.

Luego, Voila ... un DateTime de microsegundos eficiente y preciso.

Pero, encontramos que a veces el Stopwatch.GetTimestamp() devolverá un número menor.

Sucede muy raramente. Nuestro pensamiento es simplemente "reiniciar" cuando eso suceda y continuar.

SIN EMBARGO, nos hace dudar de la precisión de Stopwatch.GetTimestamp() o sospechamos que hay un error en la biblioteca .Net.

Si puede arrojar algo de luz sobre esto, por favor haga.

FYI, en función del valor actual de la marca de tiempo, la frecuencia y long.MaxValue, parece poco probable que se disipe durante nuestra vida a menos que sea un problema de hardware.

EDITAR: Ahora estamos calculando este valor "por hilo" y luego "pinchándolo" para ver si hay saltos entre los núcleos para restablecerlo.

+0

¿Cómo se puede tener un "microsegundo" tiempo exacto del sistema "cuando' UtcNow' no es microsegundo exacto? Este número solo se puede usar para intervalos precisos de intervalos. – Groo

+1

Lo siento. ¿Has leído mi explicación? Solo llama a UtcNow una vez al inicio de la aplicación. A partir de ese punto, utiliza el reloj del sistema y calcula la diferencia para obtener la hora actual. – Wayne

+0

Cronómetro usa los temporizadores de alta resolución cuando tiene acceso a ellos o existen en la computadora. –

Respuesta

4

Es posible que obtenga el salto en el tiempo porque su hilo está saltando núcleos. Consulte la "nota" en esta página: http://msdn.microsoft.com/en-us/library/ebf7z0sw.aspx

+0

Gracias! Esto sigue la lógica ya que es una aplicación multiproceso. Y su enlace da una confirmación de que un problema de hardware y BIOS puede causar esto. Te doy crédito por la respuesta. ¿Alguna sugerencia sobre cómo abordar esto? Simplemente estamos manteniendo "lastClockTime" y comparando, es menos que reiniciamos. – Wayne

+0

@Wayne: 'Environment.TickCount' aparentemente no sufre este problema, pero es menos preciso y se desborda en menos de un mes. – Groo

+0

Ya sufrimos del desbordamiento. Fue doloroso. Y es demasiado menos preciso para nuestras necesidades. Gracias por ofrecer, de todos modos. – Wayne

0

No sé exactamente respecto acerca corriendo hacia atrás (que suena como un el pequeño cambia hacia atrás), pero hasta ahora he experimentado tres veces que el valor de Stopwatch.GetTimestamp() puede cambiar tan enormemente que causa excepciones de desbordamiento en algunos cálculos posteriores de la forma aproximadamente de esta manera:
(Stopwatch.GetTimestamp() - ProgramStartStopwatchTimestamp) * n
donde n es un valor grande, pero lo suficientemente pequeño que si el cronómetro no se salta alrededor enormemente, a continuación, el programa podría ejecutar años sin tener excepción de desbordamiento. Tenga en cuenta también que estas excepciones se produjeron muchas horas después de que se inició el programa, por lo que el problema no es solo que el cronómetro se ejecutó hacia atrás un poco inmediatamente después del inicio.Simplemente saltó a un rango totalmente diferente, en cualquier dirección.

En cuanto al vuelco del cronómetro, en uno de los casos anteriores (¿no es la diferencia, pero el cronómetro?) Obtuvo el valor de algo a la 0xFF4? ???? ???? ????, por lo que saltó a un rango que estaba muy cerca de rodar. Después de reiniciar el programa varias veces, este nuevo rango todavía estaba en vigencia. Si eso importa más teniendo en cuenta la necesidad de manejar los saltos de todos modos ...

Si además fue necesario determinar qué núcleo se tomó la marca de tiempo, probablemente sea útil saber el número de núcleo de ejecución. Para este fin, hay funciones llamadas GetCurrentProcessorNumber (disponible desde Server 2003 y Vista) y GetCurrentProcessorNumberEx (disponible desde Server 2008 R2 y Windows 7). Vea también this question's answers para más opciones (incluido Windows XP).
Tenga en cuenta que el planificador puede cambiar el número de núcleo en cualquier momento. Pero cuando uno lee el número de núcleo antes de leer la marca de tiempo de Cronómetro, y después, y el número de núcleo permanece igual, entonces tal vez uno puede suponer que la lectura de Cronómetro también se realizó en este núcleo ...

Cuestiones relacionadas