¿Por qué System.nanoTime () es más lento (en rendimiento) que System.currentTimeMillis ()?

Hoy hice un poco de Benchmark para probar el rendimiento de velocidad de System.nanoTime() y System.currentTimeMillis() :

 long startTime = System.nanoTime(); for(int i = 0; i < 1000000; i++) { long test = System.nanoTime(); } long endTime = System.nanoTime(); System.out.println("Total time: "+(endTime-startTime)); 

Estos son los resultados:

 System.currentTimeMillis(): average of 12.7836022 / function call System.nanoTime(): average of 34.6395674 / function call 

¿Por qué las diferencias en la velocidad de carrera son tan grandes?

Sistema de referencia:

 Java 1.7.0_25 Windows 8 64-bit CPU: AMD FX-6100 

De este blog de Oracle :

System.currentTimeMillis() se implementa utilizando el método GetSystemTimeAsFileTime, que básicamente solo lee el valor del tiempo de baja resolución que mantiene Windows. La lectura de esta variable global es naturalmente muy rápida, alrededor de 6 ciclos según la información reportada.

System.nanoTime() se implementa utilizando la QueryPerformanceCounter/ QueryPerformanceFrequency API (si está disponible, de lo contrario, devuelve currentTimeMillis*10^6) . QueryPerformanceCounter(QPC) se implementa de diferentes maneras dependiendo del hardware en el que se ejecuta. Normalmente usará el temporizador de intervalo progtwigble (PIT) o el temporizador de administración de energía (PMT) de ACPI o el contador de marca de tiempo (TSC) de nivel de CPU. El acceso al PIT / PMT requiere la ejecución de instrucciones lentas del puerto de E / S y, como resultado, el tiempo de ejecución para QPC es del orden de microsegundos. En contraste, la lectura del TSC es del orden de 100 ciclos de reloj (para leer el TSC del chip y convertirlo a un valor de tiempo basado en la frecuencia de operación).

Tal vez esto responda la pregunta. Los dos métodos usan una cantidad diferente de ciclos de reloj, lo que resulta en una velocidad lenta de la última.

Además en ese blog en la sección de conclusión:

Si está interesado en medir / calcular el tiempo transcurrido, siempre use System.nanoTime (). En la mayoría de los sistemas dará una resolución del orden de microsegundos. Tenga en cuenta que esta llamada también puede tardar microsegundos en ejecutarse en algunas plataformas.

La mayoría de los sistemas operativos (no mencionaste cuál estás usando) tienen un contador / reloj en memoria que proporciona una precisión de milisegundos (o cerca de eso). Para precisión de nanosegundos, la mayoría tiene que leer un contador de hardware. La comunicación con el hardware es más lenta que leer algún valor que ya esté en la memoria.

Puede ser solo el caso en Windows. Vea esta respuesta a una pregunta similar.

Básicamente, System.currentTimeMillis() simplemente lee una variable global mantenida por Windows (que es lo que tiene baja granularidad), mientras que System.nanoTime() realidad tiene que hacer operaciones IO.

Estás midiendo eso en Windows, ¿verdad? Realicé este ejercicio en 2008. nanoTime ES más lento en Windows que en CurrentTimeMillis. Según recuerdo, en Linux, nanotime es más rápido que CurrentTimeMillis y es ciertamente más rápido que en Windows.

Lo importante a tener en cuenta es que si está tratando de medir el agregado de múltiples operaciones de menos de milisegundos, debe usar nanotime como si la operación terminara en menos de 1/1000 de segundo de su código, al comparar currentTimeMillis mostrará la operación como instantánea. entonces 1,000 de estos serán instantáneos. Lo que podría querer hacer es usar nanotime y luego redondear al milisegundo más cercano, por lo que si una operación tomó 8000 nanosegundos se contará como 1 milisegundo, no 0.

Lo que podría querer hacer es usar nanotime y luego redondear al milisegundo más cercano, por lo que si una operación tomó 8000 nanosegundos se contará como 1 milisegundo, no 0.

Nota aritmética:

8000 nanosegundos es 8 microsegundos es 0.008 milisegundos. Redondear llevará eso a 0 milisegundos.