Comment lancer un programme Java avec un temps d'exécution contrôlé avec précision?

Comme je le sais JVM avant de lancer une application Java, il alloue un morceau de RAM pour cela, et cette mémoire pourrait être contrôlée par l'utilisateur avant de lancer. Mais il y a un autre problème lorsque je lance une application, elle a une exécution de temps différente à chaque fois.

Voici un exemple très simple avec la boucle for:

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);
    }
}

Il imprime différents résultats:

duration = 5720542
duration = 7331307
duration = 7737946
duration = 6899173

Disons que je veux qu'il soit exécuté exactement 10 000 000 nanosecondes ou 10 millisecondes.

, Que dois-je voulez?

Je veux que l'application java soit exécutée avec l'exécution exacte de l'heure.

Pourquoi ai - je besoin de ça?

Lorsque je lance une application, je veux afficher le temps d'exécution exact laissé sur la fenêtre de démarrage de l'application avant de charger tous les composants.

Je suppose que c'est une sorte de manipulation du processeur et je voulais savoir si c'est possible ou non.

Q1: Est-ce possible en Java?
Q2: si ce N'est pas possible en Java, y a-t-il un moyen d'y parvenir en accès aux méthodes natives du système d'exploitation. par exemple en priorisant L'application Java ou autre chose?
Q3: Que diriez-vous d'enregistrer l'état d'une application dans le fichier et de le charger en mémoire?

21
demandé sur Paolo Forgia 2017-11-09 10:23:20

7 réponses

Il y a un certain nombre de sources d'incertitude dans votre mesure du temps. Et toutes ces sources n'influencent pas seulement vos mesures, c'est le temps d'exécution lui-même qui est incertain. Parmi les sources d'incertitude sont:

  • Utilisation du Cache (quelles parties de la mémoire sont mises en cache dans le CPU). Vos données peuvent être expulsées du cache par votre CPU exécutant une tâche d'arrière-plan.

  • Placement de la mémoire (la mémoire est-elle directement connectée au cœur du processeur en cours d'exécution?). Ce peut changer au fil du temps que votre processus peut être migré vers un autre noyau à tout moment.

  • Le logiciel interrompt (votre système d'exploitation préemptant votre processus pour en exécuter un autre). Peut être quelque peu atténué en exécutant sur une machine silencieuse, mais il n'y a aucune garantie que vous ne serez pas interrompu.

  • Limitation thermique (votre CPU décide qu'il fait trop chaud et baisse sa vitesse d'horloge). Il n'y a vraiment pas grand chose que vous pouvez faire à ce sujet sauf si vous êtes prêt à travailler sur certains intégrés processeur avec une vitesse d'horloge.

  • Interruptions matérielles (votre connecteur réseau a reçu des données d'une autre machine sur internet). Vous n'avez aucune influence sur le moment où cela frappe, que ce soit.

  • Latences imprévisibles (vous lisez des données à partir du disque, mais d'abord, le disque doit attendre que les données arrivent en dessous de la tête de lecture). Cela peut suivre des modèles lorsque vous répétez exactement les mêmes actions encore et encore, mais une fois que vous obtenez un rapport interruption matérielle, cela peut provoquer un retard inattendu de 1/7200 rpm * 60 s/min = 8.3 ms.

  • Garbage collection (vous posez des questions sur Java, donc vous avez un GC en arrière-plan). Même les meilleurs, les plus modernes éboueurs ne peuvent pas complètement éviter d'arrêter le monde de temps en temps. Et même quand ils n'arrêtent pas le monde, ils fonctionnent toujours en arrière-plan, introduisant du bruit d'exécution via le cache, le placement de la mémoire et les interruptions logicielles.

Ce sont probablement les plus importants sources, et il peut y en avoir d'autres. Le fait est que votre processus est jamais seul sur la machine. Sauf si vous exécutez sans système d'exploitation et désactivez toutes les interruptions matérielles, vous devez simplement vivre avec le fait que vos temps d'exécution varient d'une exécution à l'autre, et il n'y a tout simplement aucun moyen de résoudre ce problème.

40
répondu cmaster 2017-12-03 12:52:09

Ce n'est tout simplement pas possible. Tout d'abord, la mesure du temps en nanosecondes n'est pas exacte. J'ai l'impression que ce post l'explique bien.

Deuxièmement, vous n'avez aucun contrôle sur la façon dont le processeur planifie l'exécution. Il peut y avoir d'autres tâches monopolisant le temps CPU, ce qui retarde l'exécution de votre programme.

16
répondu Jerome Reinländer 2017-11-09 07:41:16

Le temps d'exécution précis du code arbitraire est non déterministe, car cela dépend d'autres choses que la machine physique fait simultanément.

Même si vous avez prévu de rendre le temps d'exécution "constant" en gardant une trace de l'horodatage de démarrage et d'un horodatage de fin planifié et en dormant le thread principal pendant la durée entre la sortie du programme, cela variera toujours, une quantité raisonnablement importante.

Quand, et pendant combien de temps, les threads s'exécutent ou attendent contrôle du programmeur.

9
répondu Bohemian 2017-11-09 07:36:13

[TL; DR] c'est très difficile/impossible.

Réponse plus longue voir Test de Planarité par ajout de chemin thèse de doctorat-méthodologie D'analyse comparative Chapitre pour certains des problèmes, y compris:

  1. autres applications ayant des ressources. C'est-à-dire ne pas avoir assez de mémoire et le système d'exploitation doit paginer les applications; ou le code s'exécute plus lentement car une autre application partage le CPU.
  2. résolution D'horloge-votre code ne va fonctionner aussi vite que votre CPU est capable. Portez-le sur un autre ordinateur et vos benchmarks pourraient vous donner des résultats très différents, alors ne l'optimisez pas uniquement pour votre système.
  3. chargement de classe-lorsque la JVM exécute le code pour la première fois, elle doit charger les classes en mémoire (généralement à partir du disque) et analyser le code d'octet afin que la première fois qu'elle s'exécute soit significativement plus lente que les fois suivantes.
  4. compilation juste à temps-lorsque la JVM charge le code d'octet pour la première fois, elle l'exécute en mode purement interprété. Une fois qu'il a exécuté un bloc de code d'octet (c'est-à-dire une fonction dans votre code) plusieurs fois (disons 10 000), il pourrait compiler cette fonction en code natif. La compilation ralentira cette exécution, mais les invocations suivantes seront plus rapides car elle exécute du code natif plutôt qu'interprété. Cependant, ce n'est pas une compilation unique et si la JVM détecte que certains chemins d'exécution dans le bloc sont favorisés, elle peut recompiler le code d'octet pour essayer d'optimiser ces chemins et cela peut entraîner plusieurs versions natives du code d'octet jusqu'à ce que la JVM stabilise le code par rapport à ses statistiques.
  5. Garbage collection-parfois, votre code sera interrompu pendant que Java appelle le garbage collector.

Donc, si vous voulez comparer votre application pour voir comment elle fonctionnerait de manière optimale, alors:

  • arrêtez autant d'autres applications que vous le pouvez;
  • exécutez le code plusieurs dizaines de milliers de fois;
  • ignorer les 10 000 à 20 000 premières exécutions (à atténuer pour le chargement de classe et la compilation JIT); et
  • ignorer les itérations lorsque le garbage collection se produit (c'est plus difficile à déterminer qu'il n'y paraît).

Il vous donnera une idée de la performance optimale, mais optimale et le monde réel sont deux choses très différentes.

6
répondu MT0 2017-11-09 09:29:46

La seule façon de se rapprocher de ce qui serait d'utiliser temps réel Java sur un système d'exploitation spécialement conçu pour soutenir l'exécution en temps réel.

5
répondu Matt McHenry 2017-11-09 19:07:46

Comme d'autres l'ont dit, il est impossible de connaître le temps exact restant en raison d'autres facteurs influençant la vitesse de votre programme. Vous pouvez cependant mettre des jalons et référencer les exécutions passées pour obtenir un temps semi-précis calculé à partir de la variance en temps réel jusqu'à présent par rapport aux exécutions précédentes, comme cela se fait lors de la copie de grands répertoires de fichiers sur Windows par exemple ou lors du téléchargement de fichiers volumineux dans Chrome.

Donc vous ne spécifiez pas votre problème exact, mais disons c'est quelque chose comme traiter 100 000 opérations qui nécessitent de contacter un système tiers sur internet et cela prend normalement environ 15 minutes pour terminer. Vous pouvez garder une trace de 1) heure de début, 2) Heure de fin prévue, et 3) partie terminée. Alors dites quand vous êtes 1/2 terminé, vous pouvez prendre le temps écoulé et dire que c'est combien de temps reste. Fondamentalement obtenez le taux d'opérations par seconde et divisez les opérations restantes par cela pour obtenir le nombre de secondes restant.

double speed = completedOperations / elapsedSeconds;
double remainingSeconds = remainingOperations / speed;

Cela peut cependant changer. Disons que vous démarrez le processus et après avoir obtenu 1/4 le chemin à travers 5 minutes que les sauvegardes hors site commencent, non seulement battre les disques de l'ordinateur, mais votre connexion internet. Maintenant, les choses se traitent à 1 / 10ème de la vitesse. Votre temps d'achèvement estimé commencera à être 20 min, puis à 5 minutes, il sera 15 min. Cependant, il ralentit à ce moment-là, donc vous n'êtes que 1/2 fait après 30 minutes, et votre temps restant à ce moment-là sera être de 30 minutes. Maintenant, dites que les sauvegardes sont terminées, vous serez réellement fait en 10 minutes, mais il dit qu'il reste 30 minutes.

Il n'y a aucun moyen de contourner un problème comme celui-ci qui est hors de votre contrôle. Vous pourriez faire quelques choses pour l'atténuer. Vous voudrez peut-être prendre la vitesse sur seulement les 30 dernières secondes de traitement. Ce sera le plus précis si les choses continuent à la vitesse actuelle. Vous pouvez enregistrer la vitesse moyenne à des moments de la journée historiquement si c'est un question. Vous pouvez faire la moyenne de la vitesse totale de course et de la vitesse de dernière minute si la vitesse fluctue.

Une autre chose qui pourrait le jeter est la variance dans les données. Par exemple, si vous regardez les clients et les traitez en fonction de la date à laquelle ils sont devenus clients, vos 10 000 premières opérations peuvent concerner des clients fidèles qui sont avec vous depuis des années et qui ont des tonnes de données à traiter, tandis que les 10 000 derniers peuvent être de nouveaux clients avec peu de données qui Vous pourriez ensuite, utilisez la quantité de données sous-jacente au lieu du nombre de clients...


Cependant, si vous voulez être exact, pour une raison quelconque (la plupart du temps), vous pourriez faux, au prix de temps. Prenez le plus grand temps d'exécution normal et utilisez simplement le temps pris depuis le début pour fournir les progrès et le temps restant. Ensuite, lorsque tout le travail réel est terminé, mettez une commande sleep() pour attendre le temps restant. Il y aura toujours une chance que la charge du système ou quelque chose le fasse prendre exceptionnellement long cependant, mais vous pouvez alors changer votre temps maximum à cette nouvelle valeur.

Les temps de vos courses sont probablement sur une sorte de courbe, plus vous faites le temps, plus il est probable qu'une seule course se terminera dans ce temps, mais plus de courses n'attendront rien:

         #            ^
         #            |
        ###           |
        ###           |
       #####          R
      #######         U
    ###########       N
###################   S

Time-------------->

Accordé cela semble stupide, mais votre application fonctionnera à des vitesses différentes en raison de variables que vous ne pouvez pas contrôler, et si un temps d'exécution presque constant est important pour vous cela est le seul moyen.

3
répondu Jason Goemaat 2017-12-04 16:52:28

Cela ne va pas marcher à votre façon. Cela dépend de l'état du système, comme la quantité de ressources système qui travaillent sur votre programme.

Comme je peux voir, vous souhaitez afficher le temps restant pour ouvrir l'application. Dans ce cas, supposons que deux utilisateurs exécutent votre programme sur des machines différentes, qui ont une structure de base et une fréquence différentes ...

Mais je peux donner une suggestion, vous pouvez simplement lire les données de votre programme et ajuster l'heure sur cette base, comme les autres demande qui montre ..% chargé ou même que la fonction de gestionnaire de téléchargement qui montre ..% télécharger.

1
répondu rajiv baghel 2017-11-09 12:13:21