Ce que j'aimerais savoir, c'est si je dois utiliser System.currentTimeMillis () ou System.nanoTime () lors de la mise à jour des positions de mon objet dans mon jeu? Leur changement de mouvement est directement proportionnel au temps écoulé depuis le dernier appel et je veux être aussi précis que possible.
J'ai lu qu'il existait de sérieux problèmes de résolution temporelle entre différents systèmes d'exploitation (à savoir que Mac/Linux a une résolution de près de 1 ms alors que Windows a une résolution de 50 ms?). J'exécute principalement mes applications sur Windows et la résolution de 50 ms semble assez imprécise.
Existe-t-il de meilleures options que les deux que j'ai énumérées?
Des suggestions/commentaires?
Si vous recherchez simplement des mesures extrêmement précises du temps écoulé , utilisez System.nanoTime()
. System.currentTimeMillis()
vous donnera le temps écoulé le plus précis possible en millisecondes depuis l'époque, mais System.nanoTime()
vous donne un temps précis en nanosecondes, par rapport à un point quelconque.
De la Java Documentation:
public static long nanoTime()
Renvoie la valeur actuelle du temporisateur système le plus précis disponible, en nanosecondes.
Cette méthode ne peut être utilisée que pour mesurer le temps écoulé et n'est liée à aucune autre notion de système ou de temps d'horloge. La valeur renvoyée représente des nanosecondes depuis un certain temps fixe mais arbitraire (peut-être dans le futur, les valeurs peuvent donc être négatives). Cette méthode fournit une précision nanoseconde, mais pas nécessairement une précision nanoseconde. Aucune garantie n'est donnée sur la fréquence à laquelle les valeurs changent. Différences d’appels successifs supérieurs à environ 292 ans (263 nanosecondes) ne calculera pas avec précision le temps écoulé en raison du débordement numérique.
Par exemple, pour mesurer le temps d’exécution d’un code, procédez comme suit:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
Voir aussi: JavaDoc System.nanoTime () et JavaDoc System.currentTimeMillis () pour plus d'informations.
Puisque personne d'autre n'en a parlé…
Il n'est pas sûr de comparer les résultats d'appels System.nanoTime()
entre différents threads. Même si les événements des fils se déroulent dans un ordre prévisible, la différence en nanosecondes peut être positive ou négative.
System.currentTimeMillis()
est sans danger pour les échanges entre les threads.
Mise à jour par Arkadiy : J'ai observé un comportement plus correct de System.currentTimeMillis()
sur Windows 7 sous Oracle Java 8. L'heure a été renvoyée avec une précision de 1 milliseconde. Le code source dans OpenJDK n'a pas changé, donc je ne sais pas ce qui cause le meilleur comportement.
David Holmes de Sun a publié il y a quelques années un article de blog qui présente de manière très détaillée les API de chronométrage Java (en particulier System.currentTimeMillis()
et System.nanoTime()
), lorsque vous le souhaitez. utiliser lequel, et comment ils fonctionnent en interne.
Un aspect très intéressant du minuteur utilisé par Java sur Windows pour les API qui ont un paramètre d'attente minuté est que la résolution du minuteur peut changer en fonction des autres appels d'API qui ont pu être passés - système juste dans le processus particulier). Il montre un exemple où Thread.sleep()
provoquera ce changement de résolution.
System.nanoTime()
n'est pas pris en charge par les anciennes machines virtuelles. Si cela vous inquiète, restez avec currentTimeMillis
En ce qui concerne l'exactitude, vous avez presque raison. Sur QUELQUES ordinateurs Windows, currentTimeMillis()
a une résolution d'environ 10 ms (et non 50 ms). Je ne sais pas pourquoi, mais certaines machines Windows sont aussi précises que des machines Linux.
J'ai utilisé GAGETimer dans le passé avec un succès modéré.
Comme d'autres l'ont déjà dit, currentTimeMillis correspond à l'heure de l'horloge, qui change en raison de l'heure d'été, des utilisateurs qui modifient les paramètres de l'heure, des secondes intercalaires et de la synchronisation de l'heure sur Internet. Si votre application dépend de l'augmentation monotone des valeurs de temps écoulé, vous préférerez peut-être nanoTime.
Vous pensez peut-être que les joueurs ne joueront pas avec les réglages de l'heure pendant le jeu, et vous auriez peut-être raison. Mais ne sous-estimez pas les perturbations dues à la synchronisation de l'heure sur Internet, ou peut-être aux utilisateurs de bureau distants. L'API nanoTime est à l'abri de ce type de perturbation.
Si vous souhaitez utiliser l'heure d'horloge tout en évitant les discontinuités dues à la synchronisation sur Internet, vous pouvez envisager un client NTP tel que Meinberg, qui "ajuste" le taux d'horloge pour le mettre à zéro, au lieu de simplement réinitialiser le horloge périodiquement.
Je parle d'expérience personnelle. Dans une application météorologique que j'ai développée, des pics de vitesse du vent se produisaient de manière aléatoire. Il m'a fallu un certain temps pour me rendre compte que ma base de temps était perturbée par le comportement de l'heure sur un PC typique. Tous mes problèmes ont disparu lorsque j'ai commencé à utiliser nanoTime. La cohérence (la monotonie) était plus importante pour mon application que la précision brute ou la précision absolue.
Oui, si une telle précision est requise, utilisez System.nanoTime()
, mais sachez que vous avez alors besoin d'une JVM Java 5+.
Sur mes XP systèmes, je vois au moins l'heure indiquée par le système. 100 microsecondes 278 nanosecondes en utilisant le code suivant:
private void test() {
System.out.println("currentTimeMillis: "+System.currentTimeMillis());
System.out.println("nanoTime : "+System.nanoTime());
System.out.println();
testNano(false); // to sync with currentTimeMillis() timer tick
for(int xa=0; xa<10; xa++) {
testNano(true);
}
}
private void testNano(boolean shw) {
long strMS=System.currentTimeMillis();
long strNS=System.nanoTime();
long curMS;
while((curMS=System.currentTimeMillis()) == strMS) {
if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)); }
}
if(shw) { System.out.println("Nano: "+(System.nanoTime()-strNS)+", Milli: "+(curMS-strMS)); }
}
Pour les graphiques de jeu et les mises à jour régulières de la position, utilisez System.nanoTime()
plutôt que System.currentTimeMillis()
. Je suis passé de currentTimeMillis () à nanoTime () dans un jeu et j'ai obtenu une amélioration visuelle majeure de la fluidité du mouvement.
Une milliseconde peut sembler devoir déjà être précise, mais ce n’est pas le cas visuellement. Les facteurs nanoTime()
peuvent être améliorés, notamment:
Comme d'autres réponses le suggèrent, si vous appelez plusieurs fois nanoTime, il est préférable de l'appeler une seule fois par image et d'utiliser la même valeur pour calculer la totalité de l'image.
J'ai eu une bonne expérience avec nanotime . Il fournit une durée d'horloge murale sous forme de deux longs (secondes depuis Epoch et de nanosecondes dans cette seconde), à l'aide d'une bibliothèque JNI. Il est disponible avec la partie JNI précompilée pour Windows et Linux.
System.currentTimeMillis()
n'est pas sûr pour le temps écoulé car cette méthode est sensible aux changements d'horloge en temps réel du système. Vous devriez utiliser System.nanoTime
. Veuillez vous référer à Java Aide système:
À propos de la méthode nanoTime:
.. Cette méthode fournit une précision nanoseconde, mais pas nécessairement une résolution nanoseconde (c'est-à-dire à quelle fréquence la valeur change) - aucune garantie n'est donnée, si ce n'est que la résolution est au moins aussi bonne que celle de currentTimeMillis () ..
Si vous utilisez System.currentTimeMillis()
votre temps écoulé peut être négatif (Retour <- vers le futur)