son - Tiempo de microsegundo en JavaScript
pasar de mseg a seg (4)
¿Hay alguna función de tiempo en JavaScript con una resolución de microsegundos?
Soy consciente de timer.js para Chrome, y espero que haya una solución para otros navegadores amigables, como Firefox, Safari, Opera, Epiphany, Konqueror, etc. No estoy interesado en apoyar ningún IE, pero las respuestas incluyen IE son bienvenidos.
(Dada la poca precisión del tiempo de milisegundos en JS, ¡no estoy conteniendo la respiración en este caso!)
Actualización: timer.js anuncia una resolución de microsegundos, pero simplemente multiplica la lectura en milisegundos por 1,000. Verificado por prueba e inspección de código. Decepcionado. : [
Ahora hay un nuevo método para medir microsegundos en javascript: http://gent.ilcore.com/2012/06/better-timer-for-javascript.html
Sin embargo, en el pasado, encontré un método crudo para obtener una precisión de 0.1 milisegundos en JavaScript de un temporizador de milisegundos. ¿Imposible? Nop. Sigue leyendo:
Estoy haciendo algunos experimentos de alta precisión que requieren precisiones del temporizador autocomprobadas, y descubrí que era capaz de obtener de manera confiable una precisión de 0.1 milisegundos con ciertos navegadores en ciertos sistemas.
He descubierto que en los modernos navegadores web acelerados por GPU en sistemas rápidos (por ejemplo, i7 quad core, donde varios núcleos están inactivos, solo en la ventana del navegador) - ahora puedo confiar en que los temporizadores serán precisos en milisegundos. De hecho, se ha vuelto tan preciso en un sistema i7 inactivo, he podido obtener de manera confiable el mismo milisegundo exacto, en más de 1.000 intentos. Solo cuando intento hacer cosas como cargar una página web adicional u otra, la precisión en milisegundos se degrada (y puedo capturar mi propia precisión degradada haciendo una verificación de antes y después, para ver si mi tiempo de procesamiento se alarga repentinamente a 1 o más milisegundos, esto me ayuda a invalidar los resultados que probablemente se han visto afectados adversamente por las fluctuaciones de la CPU).
Se ha vuelto tan preciso en algunos navegadores acelerados de GPU en sistemas quad-core i7 (cuando la ventana del navegador es la única ventana), que he encontrado que deseaba poder acceder a un temporizador de precisión de 0.1ms en JavaScript, ya que la precisión finalmente es ahora en algunos sistemas de exploración de alta gama para que la precisión de los temporizadores valga la pena para ciertos tipos de aplicaciones de nicho que requieren alta precisión, y donde las aplicaciones son capaces de autoverificar las desviaciones de precisión.
Obviamente, si está haciendo varias pasadas, simplemente puede ejecutar varias pasadas (por ejemplo, 10 pasadas) y luego dividir entre 10 para obtener una precisión de 0,1 milisegundos. Ese es un método común para obtener una mejor precisión: hacer pases múltiples y dividir el tiempo total entre la cantidad de pases.
SIN EMBARGO ... Si solo puedo hacer un solo pase de referencia de una prueba específica debido a una situación inusualmente única, descubrí que puedo obtener una precisión de 0.1 (ya veces 0.01ms) al hacer esto:
Inicialización / Calibración:
- Ejecute un bucle ocupado para esperar hasta que el temporizador incremente al siguiente milisegundo (alinee el temporizador con el inicio del siguiente intervalo de milisegundos). Este ciclo ocupado dura menos de un milisegundo.
- Ejecute otro ciclo ocupado para incrementar un contador mientras espera que el temporizador incremente. El contador te dice cuántos incrementos de contador ocurrieron en un milisegundo. Este ciclo ocupado dura un milisegundo completo.
- Repita lo anterior, hasta que los números se vuelvan ultraestables (tiempo de carga, compilador JIT, etc.). 4. NOTA : La estabilidad del número le brinda la precisión que puede obtener en un sistema inactivo. Puede calcular la varianza, si necesita verificar la precisión. Las variaciones son mayores en algunos navegadores y más pequeñas en otros navegadores. Más grande en sistemas más rápidos y más lento en sistemas más lentos. La consistencia también varía Puede decir qué navegadores son más consistentes / precisos que otros. Los sistemas más lentos y los sistemas ocupados generarán mayores variaciones entre los pasos de inicialización. Esto puede darle la oportunidad de mostrar un mensaje de advertencia si el navegador no le proporciona la precisión suficiente para permitir mediciones de 0.1 ms o 0.01 ms. El sesgo del temporizador puede ser un problema, pero algunos temporizadores de milisegundos enteros en algunos sistemas aumentan de forma bastante precisa (bastante a la derecha en el punto), lo que dará como resultado valores de calibración muy consistentes en los que puede confiar.
- Guarde el valor del contador final (o el promedio de los últimos pases de calibración)
Evaluación comparativa de un pase con precisión de menos de milisegundos:
- Ejecute un ciclo ocupado para esperar hasta que el temporizador incremente al siguiente milisegundo (alinee el temporizador con el inicio del siguiente intervalo de milisegundos). Este ciclo ocupado dura menos de un milisegundo.
- Ejecute la tarea que desea comparar con precisión el tiempo.
- Verifica el cronómetro Esto le da los milisegundos enteros.
- Ejecute un ciclo ocupado final para incrementar un contador mientras espera que el temporizador incremente. Este ciclo ocupado dura menos de un milisegundo.
- Divida este valor del contador por el valor del contador original desde la inicialización.
- Ahora tienes la parte decimal de milisegundos !!!!!!!!
ADVERTENCIA: Los bucles ocupados NO se recomiendan en los navegadores web, pero, afortunadamente, estos bucles ocupados se ejecutan durante menos de 1 milisegundo cada uno, y solo se ejecutan unas pocas veces.
Variables como la compilación JIT y las fluctuaciones de la CPU añaden inexactitudes masivas, pero si ejecuta varias pasadas de inicialización, tendrá una recompilación dinámica completa y, finalmente, el contador se estabilizará en algo muy preciso. Asegúrese de que todos los bucles ocupados tengan exactamente la misma función para todos los casos, de modo que las diferencias en los bucles ocupados no generen diferencias. Asegúrese de que todas las líneas de código se ejecuten varias veces antes de comenzar a confiar en los resultados, para permitir que los compiladores JIT ya se hayan estabilizado a una recompilación dinámica completa (dynarec).
De hecho, fui testigo de que la precisión se acercaba a microsegundos en ciertos sistemas, pero aún no confiaba en él. Pero la precisión de 0.1 milisegundos parece funcionar con bastante fiabilidad, en un sistema inactivo de cuatro núcleos donde soy la única página del navegador. Llegué a un caso de prueba científica donde solo podía hacer pases únicos (debido a la presencia de variables únicas), y necesitaba calcular con precisión cada pasada, en lugar de promediar múltiples pases de repetición, por eso lo hice.
Hice varios pases previos y pases ficticios (también para ajustar el dynarec), para verificar la confiabilidad de 0.1 ms de precisión (permanecí sólido por varios segundos), luego mantuve mis manos alejadas del teclado / mouse, mientras el punto de referencia ocurría, luego hice varios pases posteriores para verificar la confiabilidad de la precisión de 0.1 ms (se mantuvo sólida de nuevo). Esto también verifica que cosas como cambios de estado de energía u otras cosas, no ocurrieron entre el antes y el después, interfiriendo con los resultados. Repita la prueba previa y la prueba posterior entre cada pase de referencia único. Después de esto, estaba prácticamente seguro de que los resultados entre ellos eran precisos. No hay garantía, por supuesto, pero demuestra que en algunos casos es posible una precisión precisa de <0,1 ms en un navegador web.
Este método solo es útil en casos muy específicos . Aun así, literalmente no será 100% infinitamente garantizable, puede obtener una precisión muy confiable, e incluso una precisión científica cuando se combina con varias capas de verificaciones internas y externas.
Aquí hay un ejemplo que muestra mi temporizador de alta resolución para node.js :
function startTimer() {
const time = process.hrtime();
return time;
}
function endTimer(time) {
function roundTo(decimalPlaces, numberToRound) {
return +(Math.round(numberToRound + `e+${decimalPlaces}`) + `e-${decimalPlaces}`);
}
const diff = process.hrtime(time);
const NS_PER_SEC = 1e9;
const result = (diff[0] * NS_PER_SEC + diff[1]); // Result in Nanoseconds
const elapsed = result * 0.0000010;
return roundTo(6, elapsed); // Result in milliseconds
}
Uso:
const start = startTimer();
console.log(''test'');
console.log(`Time since start: ${endTimer(start)} ms`);
Normalmente, es posible que pueda usar:
console.time(''Time since start'');
console.log(''test'');
console.timeEnd(''Time since start'');
Si está cronometrando secciones de código que implican bucles, no puede obtener acceso al valor de console.timeEnd()
para agregar los resultados de su temporizador. Puedes, pero se pone desagradable porque tienes que inyectar el valor de tu variable de iteración, como i
, y establecer una condición para detectar si el ciclo está hecho.
Aquí hay un ejemplo porque puede ser útil:
const num = 10;
console.time(`Time til ${num}`);
for (let i = 0; i < num; i++) {
console.log(''test'');
if ((i+1) === num) { console.timeEnd(`Time til ${num}`); }
console.log(''...additional steps'');
}
Cite: https://nodejs.org/api/process.html#process_process_hrtime_time
La respuesta es "no", en general. Si usa JavaScript en algún entorno del lado del servidor (es decir, no en un navegador), entonces todas las apuestas están desactivadas y puede intentar hacer lo que quiera.
editar - esta respuesta es vieja; los estándares han progresado y las instalaciones más nuevas están disponibles como soluciones al problema del tiempo preciso. Aun así, debe recordarse que fuera del dominio de un verdadero sistema operativo en tiempo real, el código ordinario no privilegiado tiene un control limitado sobre su acceso a los recursos informáticos. Medir el rendimiento no es lo mismo (necesariamente) que predecir el rendimiento.
Como se alude en la respuesta de Mark Rejhon, hay una API disponible en los navegadores modernos que expone los datos de tiempo de resolución de milisegundos a la secuencia de comandos: el temporizador de alta resolución W3C , también window.performance.now()
como window.performance.now()
.
now()
es mejor que el Date.getTime()
tradicional en dos formas importantes:
now()
es un duplicado con una resolución de submilisegundos que representa el número de milisegundos desde el inicio de la navegación de la página. Devuelve el número de microsegundos en el fraccionario (por ejemplo, un valor de 1000.123 es 1 segundo y 123 microsegundos).now()
es monótonamente creciente. Esto es importante ya queDate.getTime()
puede saltar hacia delante o hacia atrás en llamadas posteriores. En particular, si la hora del sistema del sistema operativo se actualiza (por ejemplo, la sincronización del reloj atómico),Date.getTime()
también se actualiza.now()
se garantiza que siempre será monótonamente creciente, por lo que no se verá afectado por el tiempo del sistema del sistema operativo; siempre será el reloj de pared (suponiendo que el reloj de pared no sea atómico ...).
now()
se puede usar en casi todos los lugares en los que son new Date.getTime()
, + new Date
y Date.now()
. La excepción es que Date
y now()
veces no se mezclan, como Date
se basa en unix-epoch (el número de milisegundos desde 1970), mientras que now()
es el número de milisegundos desde que comenzó la navegación de la página (por lo que ser mucho más pequeño que Date
).
now()
es compatible con Chrome estable, Firefox 15+ e IE10. También hay varios polyfills disponibles.