2011-04-12 12 views
41

Cuando se mide el tiempo transcurrido en un nivel bajo, que tiene la opción de usar cualquiera de estos:Tiempo de medición de gastos generales en Java

System.currentTimeMillis(); 
System.nanoTime(); 

se implementan Ambos métodos native. Antes de profundizar en cualquier código C, ¿alguien sabe si hay alguna sobrecarga sustancial llamando a uno u otro? Quiero decir, si realmente no me importa la precisión adicional, ¿cuál se esperaría que tomara menos tiempo de CPU?

N.B: Estoy usando el estándar de Java JDK 1.6, pero la pregunta puede ser válido para cualquier JRE ...

+1

Tenga en cuenta que 'nanoTime' no se correlaciona con el tiempo real y solo debe usarse para medir cuánto tiempo tomó algo. – Powerlord

+0

@ R.Bemrose, gracias, lo sé. Es realmente para medir cuánto tiempo lleva algo. –

Respuesta

25

no creo que hay que preocuparse por la sobrecarga de cualquiera. Es tan mínimo que apenas se puede medir. Aquí hay una rápida micro de referencia de ambos:

for (int j = 0; j < 5; j++) { 
    long time = System.nanoTime(); 
    for (int i = 0; i < 1000000; i++) { 
     long x = System.currentTimeMillis(); 
    } 
    System.out.println((System.nanoTime() - time) + "ns per million"); 

    time = System.nanoTime(); 
    for (int i = 0; i < 1000000; i++) { 
     long x = System.nanoTime(); 
    } 
    System.out.println((System.nanoTime() - time) + "ns per million"); 

    System.out.println(); 
} 

Y el último resultado:

14297079ns per million 
29206842ns per million 

sí parece que es System.currentTimeMillis() doble de rápido que System.nanoTime(). Sin embargo, 29ns va a ser mucho más corto que cualquier otra cosa que medirías de todos modos. Me gustaría obtener System.nanoTime() para obtener precisión y precisión ya que no está asociado con relojes.

+1

Buen punto de referencia. En mi computadora, es lo contrario. Obtengo esta salida: 17258920ns por millón, 14974586ns por millón. Lo que significa que realmente depende de JVM, procesadores, sistemas operativos, etc. Aparte de eso, la diferencia es casi irrelevante. Gracias por la buena respuesta! –

+0

No hay problema. Sí, estoy seguro de que hay todo tipo de factores que harán que varíe.De cualquier forma, parece que tendrías que llamarla millones de veces por segundo en una máquina moderna para que esté causando un tiempo de sincronización notable. – WhiteFang34

+0

SO subyacente sería interesante. Sospecho que si la implementación usa 'clock_gettime()' de POSIX, la diferencia sería ~ 0. – ninjalj

6

System.currentTimeMillis() es generalmente muy rápido (afaik 5-6 ciclos de CPU pero no sé dónde lo he leído más), pero su resolución varía en diferentes plataformas.

Así que si necesita alta precisión, vaya a nanoTime(), si le preocupa la sobrecarga, vaya a currentTimeMillis().

+0

Buen punto. Mira la respuesta de WhiteFang34. Parecen ser algo igualmente rápidos, según el sistema utilizado para compararlos. –

11

Solo debe utilizar System.nanoTime() para medir el tiempo que tarda en ejecutarse. No es solo una cuestión de precisión de nanosegundos, System.currentTimeMillis() es "tiempo de reloj de pared", mientras que System.nanoTime() está diseñado para cronometrar las cosas y no tiene los caprichos del "tiempo del mundo real" que tiene el otro. Desde el Javadoc de System.nanoTime():

Este método sólo se puede utilizar para medir el tiempo transcurrido y no está relacionado con ninguna otra noción de sistema o de pared reloj de tiempo.

+0

Sí, sé que Javadoc menciona esto. Pero ambos se pueden usar de manera equivalente si se miden cosas entre 1 y 10 ms muchas veces. ¿Qué quieres decir con "caprichos del tiempo del mundo real"? –

+3

@Lukas: El problema es que 'System.currentTimeMillis()' puede (creo) hacer cosas como insertar pequeños ajustes de reloj que descontarían los tiempos. Raro, probablemente, pero 'nanoTime()' está destinado a mediciones que no deberían verse afectadas por ese tipo de cosas. – ColinD

+0

que tiene sentido –

2

A nivel teórico, para una máquina virtual que utiliza hilos nativos, y se sienta en un sistema operativo preventivo moderna, los currentTimeMillis se pueden implementar para ser leído sólo una vez por segmento de tiempo. Presumiblemente, las implementaciones de nanoTime no sacrificarían la precisión.

+0

Ese es un buen punto acerca de la precisión. Si tiene razón, entonces 'currentTimeMillis()' no podría ser más preciso. O porque no necesita ser preciso, se puede implementar de esa manera. Pero, por otro lado, eso no dice cuál es más rápido ... –

6

Si tienes tiempo, mira this talk by Cliff Click, habla del precio de System.currentTimeMillis, entre otras cosas.

+0

Bien, gracias. Lo investigaré –

39

La respuesta correcta en esta página no es correcta. Esa no es una forma válida de escribir un punto de referencia debido a la eliminación de código muerto (DCE) de JVM, reemplazo en la pila (OSR), desenrollado de bucles, etc. Solo un marco como el marco de micro-benchmarking JMH de Oracle puede medir algo así. Lea this post si tiene alguna duda sobre la validez de dichos micro benchmarks.

Aquí es un punto de referencia JMH para System.currentTimeMillis() vs System.nanoTime():

@BenchmarkMode(Mode.AverageTime) 
@OutputTimeUnit(TimeUnit.NANOSECONDS) 
@State(Scope.Benchmark) 
public class NanoBench { 
    @Benchmark 
    public long currentTimeMillis() { 
     return System.currentTimeMillis(); 
    } 

    @Benchmark 
    public long nanoTime() { 
    return System.nanoTime(); 
    } 
} 

Y aquí están los resultados (en un procesador Intel Core i5):

Benchmark       Mode Samples  Mean Mean err Units 
c.z.h.b.NanoBench.currentTimeMillis avgt  16 122.976  1.748 ns/op 
c.z.h.b.NanoBench.nanoTime   avgt  16 117.948  3.075 ns/op 

lo que demuestra que System.nanoTime() es ligeramente más rápido en ~ 118ns por invocación en comparación con ~ 123ns. Sin embargo, también está claro que una vez que se tiene en cuenta el error medio, hay muy poca diferencia entre los dos. Los resultados también pueden variar según el sistema operativo. Pero la conclusión general debería ser que son esencialmente equivalentes en términos de sobrecarga.

ACTUALIZACIÓN 2015/08/25: Si bien esta respuesta está más cerca de corregir la mayoría, utilizando JMH para medir, todavía no es correcta. Medir algo como System.nanoTime() en sí mismo es un tipo especial de benchmarking retorcido. La respuesta y el artículo definitivo es here.

+0

¡Uso maravilloso de JMH! Deseo que más microbenchmarks en este sitio lo aprovechen. –

+0

Quería probar tu ejemplo y me preguntaba por qué la anotación '@ GenerateMicroBenchmark' no funciona. Parece que ha cambiado su nombre a '@ Benchmark' más o menos recientemente. – dajood

+0

He editado para seguirte, @dajood – Oliv

4

La respuesta aceptada a esta pregunta es incorrecta. La respuesta alternativa provista por @brettw es buena pero, sin embargo, poco esclarecedora.

Para un tratamiento completo de este tema y el costo real de estas llamadas, por favor ver https://shipilev.net/blog/2014/nanotrusting-nanotime/

Para responder a la pregunta:

¿alguien sabe si hay alguna sobrecarga sustancial llamando a uno o ¿el otro?

  • La sobrecarga de llamar System#nanoTime es de entre 15 a 30 nanosegundos por llamada.
  • El valor reportado por nanoTime, su resolución, sólo cambia una vez por 30 nanosegundos

Esto significa dependiendo de si usted está tratando de hacer millones de peticiones por segundo, llamando nanoTime significa que está perdiendo una gran eficacia parte de la segunda llamada nanoTime. Para estos casos de uso, considere la posibilidad de medir las solicitudes desde el lado del cliente, asegurándose así de que no caiga en el coordinated omission, la medición de la profundidad de la cola también es un buen indicador.

Si no está tratando de meter todo el trabajo que pueda en un solo segundo, entonces nanoTime en realidad no importará, pero la omisión coordinada sigue siendo un factor.

Finalmente, para completar, currentTimeMillis no se puede utilizar sin importar su costo. Esto se debe a que no se garantiza que avance entre dos llamadas. Especialmente en un servidor con NTP, currentTimeMillis se mueve constantemente. Sin mencionar que la mayoría de las cosas medidas por una computadora no toman un milisegundo completo.

+0

Gracias por los comentarios. Mientras tanto, también me encontré con ese artículo de Aleksey Shipilëv. ¿Le importaría poner la esencia de ese artículo como respuesta a mi pregunta concreta sobre desbordamiento de pila, en el espíritu de Stack Overflow (que es tener una respuesta completa, posiblemente respaldada por más detalles en enlaces en Stack Overflow directamente)? Voy a aceptar tu respuesta, entonces. –

+0

No estoy haciendo esto para obtener una respuesta aceptada. En última instancia, el problema es que la respuesta aceptada es orientar a las personas en la dirección equivocada, lo que es desafortunado. – pjulien

+0

Lo actualicé desde que me lo preguntó, pero al mismo tiempo, siempre me siento corto. Las respuestas como esta de StackOverflow solo me piden problemas ya que siempre dejan demasiado espacio para la interpretación. – pjulien

Cuestiones relacionadas