temporizador - ¿Cómo lanzar un programa Java con tiempo de ejecución controlado con precisión?
runtime.getruntime().exec java ejemplo (7)
Como han dicho otros, es imposible saber el tiempo exacto restante debido a otros factores que influyen en la velocidad de su programa. Sin embargo, puede poner hitos y hacer referencia a ejecuciones pasadas para obtener un tiempo semi-exacto calculado a partir de la variación en el tiempo real hasta ahora en esta ejecución en comparación con ejecuciones previas, como se hace al copiar grandes directorios de archivos en Windows, por ejemplo, o al descargar grandes Archivos en Chrome.
Por lo tanto, no especifica su problema exacto, pero digamos que es algo así como procesar 100.000 operaciones que requieren contactar a un sistema de terceros en Internet y normalmente toma alrededor de 15 minutos completarla. Puede realizar un seguimiento de 1) Hora de inicio, 2) Hora de finalización esperada y 3) Parte completada. Así que diga que cuando haya terminado 1/2, podría tomar el tiempo transcurrido y decir que es cuánto tiempo queda. Básicamente, obtenga la tasa en operaciones por segundo y divida las operaciones restantes entre eso para obtener la cantidad de segundos restantes.
double speed = completedOperations / elapsedSeconds;
double remainingSeconds = remainingOperations / speed;
Esto puede cambiar sin embargo. Supongamos que comienza el proceso y después de completar 1/4 en 5 minutos, se inician las copias de seguridad fuera del sitio, no solo golpeando los discos de la computadora, sino también su conexión a Internet. Ahora las cosas se están procesando a 1/10 de la velocidad. Su tiempo estimado de finalización comenzará en 20 minutos, luego a los 5 minutos será de 15 minutos. Sin embargo, se ralentiza en ese momento, por lo que solo se realiza la mitad después de 30 minutos, y el tiempo restante en ese momento será de 30 minutos. Ahora diga que las copias de seguridad se completaron, en realidad lo harán en 10 minutos, pero dice que quedan 30 minutos.
No hay manera de evitar un problema como este que esté fuera de su control. Podrías hacer un par de cosas para mitigarla. Es posible que desee tomar la velocidad solo durante los últimos 30 segundos de procesamiento. Eso será lo más preciso si las cosas continúan a la velocidad actual. Podría registrar la velocidad promedio a las horas del día históricamente si eso es un problema. Podría promediar la velocidad total de carrera y la velocidad de último minuto si la velocidad fluctúa.
Otra cosa que podría arrojarla es la variación en los datos. Por ejemplo, si está buscando clientes y procesándolos en función de la fecha en que se convirtieron en clientes, sus primeras 10,000 operaciones podrían ser clientes leales que han estado con usted durante años y tienen toneladas de datos para procesar, mientras que los últimos 10,000 pueden ser nuevos clientes. Con pocos datos que procesan más rápido. Entonces podría usar la cantidad de datos subyacente en lugar del recuento de clientes ...
Sin embargo, si quieres ser exacto por alguna razón (la mayoría de las veces), podrías hacerlo a costa del tiempo. Tome el mayor tiempo de ejecución normal y solo use la cantidad de tiempo que lleva desde el inicio para proporcionar el progreso y el tiempo restante. Luego, cuando haya terminado todo el trabajo, ponga un comando sleep()
para esperar el tiempo restante. Sin embargo, siempre habrá una posibilidad de que la carga del sistema o algo lo lleve a ser excepcionalmente largo, pero luego podría cambiar su tiempo máximo a ese nuevo valor.
Los tiempos de tus carreras probablemente se encuentren en algún tipo de curva, cuanto más tiempo hagas, más probabilidades habrá de que una única carrera se complete en ese tiempo, pero luego más de las carreras no esperarán nada:
# ^
# |
### |
### |
##### R
####### U
########### N
################### S
Time-------------->
Por supuesto, esto parece tonto, pero su aplicación se ejecutará a diferentes velocidades debido a las variables que no puede controlar, y si un tiempo de ejecución casi constante es importante para usted, esta es la única manera.
Como sé JVM antes de lanzar una aplicación Java, asigna un poco de RAM, y esta memoria podría ser controlada por el usuario antes de iniciar. Pero hay otro problema cuando lanzo una aplicación que tiene una ejecución de tiempo diferente cada vez.
Aquí hay un ejemplo muy simple con for loop:
package timespent;
public class Main {
public static void main(String[] args) {
long startTime = System.nanoTime();
int j = 0;
for (int i = 0; i < 1.E6; i++) {
j = i + 1;
}
long endTime = System.nanoTime();
long duration = (endTime - startTime);
System.out.println("duration = " + duration);
}
}
Imprime diferentes resultados:
duration = 5720542
duration = 7331307
duration = 7737946
duration = 6899173
Digamos que quiero que se ejecute exactamente 10,000,000 nanosegundos o 10 milisegundos.
¿Qué quiero?
Quiero que la aplicación Java se ejecute con la ejecución exacta del tiempo.
¿Por qué necesito esto?
Cuando lanzo una aplicación, quiero mostrar el tiempo de ejecución exacto que queda en la ventana de inicio de la aplicación antes de que cargue todos los componentes.
Supongo que este es un tipo de manipulación de la CPU y quería saber si es posible o no.
Q1: ¿Es posible en Java?
P2: Si no es posible en Java, entonces hay alguna forma de lograrlo accediendo a métodos nativos del sistema operativo. Por ejemplo, dando prioridad a la aplicación Java o algo más?
P3: ¿Qué hay de guardar el estado de una aplicación en el archivo y cargarlo en la memoria?
El tiempo de ejecución preciso del código arbitrario no es determinista, ya que depende de otras cosas que la máquina física está haciendo simultáneamente.
Incluso si planeaba hacer que el tiempo de ejecución sea "constante" al hacer un seguimiento de la marca de tiempo de inicio y una marca de tiempo final planificada y dormir en el hilo principal durante el tiempo que transcurrió desde que salió del programa, esto todavía variará, una cantidad razonablemente grande.
Cuándo, y durante cuánto tiempo, los subprocesos ejecutados o en espera están fuera del control del programador.
Hay una serie de fuentes de incertidumbre en su medición del tiempo. Y todas estas fuentes no solo están influenciando sus mediciones, sino que el tiempo de ejecución en sí mismo es incierto. Entre las fuentes de incertidumbre se encuentran:
Uso de caché (qué partes de la memoria se almacenan en caché dentro de la CPU). Sus datos pueden ser desalojados de la caché por su CPU ejecutando una tarea en segundo plano.
Colocación de la memoria (¿la memoria está conectada directamente al núcleo de la CPU en ejecución?). Esto puede cambiar con el tiempo, ya que su proceso puede migrarse a otro núcleo en cualquier momento.
Interrupciones de software (su sistema operativo está adelantando su proceso para ejecutar uno diferente). Puede mitigarse un poco al correr en una máquina silenciosa, pero no hay garantía de que no lo interrumpan.
Regulación térmica (su CPU decide que está demasiado caliente y reduce su velocidad de reloj). Realmente no hay mucho que puedas hacer al respecto a menos que estés preparado para trabajar en un procesador integrado con una velocidad de reloj fija.
Interrupciones de hardware (su conector de red recibió algunos datos de otra máquina en Internet). No tienes influencia en cuando esto golpea, en absoluto.
Latencias impredecibles (está leyendo algunos datos del disco, pero primero, el disco debe esperar hasta que los datos lleguen por debajo del cabezal de lectura). Esto puede seguir patrones cuando repite exactamente las mismas acciones una y otra vez, pero una vez que obtiene una interrupción de hardware no relacionada, esto puede causar un retraso inesperado de
1/7200 rpm * 60 s/min = 8.3 ms
.Recolección de basura (está preguntando sobre Java, por lo que tiene un GC ejecutándose en segundo plano). Incluso los mejores y más modernos recolectores de basura no pueden evitar detener el mundo de vez en cuando. E incluso cuando no detienen al mundo, todavía se ejecutan en segundo plano, introduciendo ruido de tiempo de ejecución a través de la caché, la ubicación de la memoria y las interrupciones del software.
Estas son probablemente las fuentes más importantes, y puede haber otras. El punto es que su proceso nunca está solo en la máquina. A menos que se ejecute sin un sistema operativo y deshabilite todas las interrupciones de hardware, solo tiene que vivir con el hecho de que sus tiempos de ejecución variarán de una ejecución a otra, y simplemente no hay manera de solucionarlo.
La única manera de acercarse a esto sería usar Java en tiempo real en un sistema operativo diseñado específicamente para soportar la ejecución en tiempo real.
No va a funcionar a tu manera. Depende del estado del sistema, como la cantidad de recursos del sistema que están trabajando en su programa.
Como puedo ver, desea mostrar el tiempo restante para abrir la aplicación. En ese caso, suponga que dos usuarios ejecutan su programa en diferentes máquinas, que tienen una estructura central y una frecuencia de reloj diferentes ...
Pero puedo dar una sugerencia, simplemente puede leer los datos de su programa y ajustar el tiempo sobre esa base, al igual que otras aplicaciones, que muestra ..% cargado o igual que la función de administrador de descargas que muestra ..% descargado.
Simplemente no es posible. En primer lugar, medir el tiempo en nanosegundos no es exacto. Siento que este post lo explica bien.
En segundo lugar, no tiene control sobre cómo la CPU programa la ejecución. Puede haber otras tareas que acaparan el tiempo de CPU, lo que retrasa la ejecución de su programa.
[TL; DR] Es muy difícil / imposible.
Para una respuesta más larga, consulte la tesis doctoral sobre Pruebas de planariedad por adición de ruta: Capítulo de metodología de evaluación comparativa para conocer algunos de los temas que incluyen:
- Otras aplicaciones que tienen recursos. Es decir, no tener suficiente memoria y el sistema operativo tiene que paginar las aplicaciones; o código que se ejecuta más lentamente ya que otra aplicación está compartiendo la CPU.
- Resolución del reloj: su código solo se ejecutará tan rápido como su CPU sea capaz. Pórtelo a otra computadora y sus puntos de referencia podrían darle resultados muy diferentes, así que no lo optimice solo para su sistema.
- Carga de clases: cuando la JVM ejecuta por primera vez el código, tiene que cargar las clases en la memoria (normalmente desde el disco) y analizar el código de bytes para que la primera vez que se ejecute sea significativamente más lento que los tiempos subsiguientes.
- Compilación Just-In-Time: cuando la JVM carga por primera vez el código de byte, lo ejecutará en un modo puramente interpretado. Una vez que haya ejecutado un bloque de código de bytes (es decir, una función dentro de su código) varias veces (por ejemplo, 10,000) podría compilar esa función a código nativo. La compilación ralentizará esa ejecución, pero luego las invocaciones posteriores serán más rápidas, ya que se ejecuta código nativo, en lugar de interpretarse. Sin embargo, esto no es una compilación de una sola vez y si la JVM detecta que ciertas rutas de ejecución dentro del bloque están siendo favorecidas, entonces puede volver a compilar el código de bytes para tratar de optimizar esas rutas y esto puede resultar en múltiples versiones nativas de los bytes. código hasta que la JVM estabiliza el código contra sus estadísticas.
- Recolección de basura: a veces su código se interrumpirá mientras Java invoca al recolector de basura.
Entonces, si desea evaluar su aplicación para ver cómo se ejecutaría de manera óptima, entonces:
- Detenga tantas otras aplicaciones como pueda;
- Ejecuta el código muchas decenas de miles de veces;
- Ignore las primeras 10,000 - 20,000 ejecuciones (para mitigar la carga de clases y la compilación JIT); y
- Ignore las iteraciones cuando se produce la recolección de basura (esto es más difícil de determinar de lo que parece).
Le dará una idea del rendimiento óptimo, pero el mundo real y óptimo son dos cosas muy diferentes.