Comme documenté dans le billet de blog Attention à System.nanoTime () en Java , sur les systèmes x86, System.nanoTime () de Java renvoie la valeur de temps en utilisant un compteur spécifique au processeur . Considérons maintenant le cas suivant que j'utilise pour mesurer le temps d'un appel:
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
Or, dans un système multicœur, il se pourrait qu'après la mesure du temps1, le thread soit planifié sur un processeur différent dont le compteur est inférieur à celui de la CPU précédente. Ainsi, nous pourrions obtenir une valeur dans time2 qui est inférieure à time1. Ainsi, nous aurions une valeur négative en timeSpent.
Compte tenu de ce cas, n'est-ce pas que System.nanotime est pratiquement inutile pour le moment?
Je sais que la modification de l'heure du système n'affecte pas le nanotime. Ce n'est pas le problème que je décris ci-dessus. Le problème est que chaque CPU conservera un compteur différent depuis sa mise sous tension. Ce compteur peut être inférieur sur la deuxième CPU par rapport à la première CPU. Étant donné que le thread peut être planifié par le système d'exploitation sur le deuxième processeur après avoir obtenu time1, la valeur de timeSpent peut être incorrecte et même négative.
Réponses:
Cette réponse a été écrite en 2011 du point de vue de ce que faisait réellement le Sun JDK de l'époque fonctionnant sur les systèmes d'exploitation de l'époque. C'était il y a très longtemps! La réponse de leventov offre une perspective plus actuelle.
Ce message est faux et
nanoTime
est sûr. Il y a un commentaire sur l'article qui renvoie à un article de blog de David Holmes , un gars du temps réel et de la concurrence chez Sun. Ça dit:Donc, sous Windows, c'était un problème jusqu'à WinXP SP2, mais ce n'est pas le cas maintenant.
Je ne trouve pas de partie II (ou plus) qui parle d'autres plates-formes, mais cet article comprend une remarque que Linux a rencontré et résolu le même problème de la même manière, avec un lien vers la FAQ pour clock_gettime (CLOCK_REALTIME) , qui dit:
Donc, si le lien de Holmes peut être lu comme impliquant des
nanoTime
appelsclock_gettime(CLOCK_REALTIME)
, alors c'est sûr à partir du noyau 2.6.18 sur x86, et toujours sur PowerPC (car IBM et Motorola, contrairement à Intel, savent en fait comment concevoir des microprocesseurs).Il n'y a malheureusement aucune mention de SPARC ou de Solaris. Et bien sûr, nous n'avons aucune idée de ce que font les JVM IBM. Mais les JVM Sun sur Windows et Linux modernes réussissent parfaitement.
EDIT: Cette réponse est basée sur les sources qu'elle cite. Mais je crains toujours que cela soit complètement faux. Des informations plus récentes seraient vraiment précieuses. Je viens de tomber sur un lien vers un article plus récent de quatre ans sur les horloges de Linux qui pourrait être utile.
la source
void foo() { Thread.sleep(40); }
un temps négatif (-380 ms!) En utilisant un seulAthlon 64 X2 4200+
processeurJ'ai fait un peu de recherche et j'ai trouvé que si quelqu'un est pédant, alors oui, cela pourrait être considéré comme inutile ... dans des situations particulières ... cela dépend de la sensibilité temporelle de vos exigences ...
Consultez cette citation du site Java Sun:
Java a également une mise en garde pour la méthode nanoTime () :
Il semblerait que la seule conclusion qui puisse être tirée est que nanoTime () ne peut pas être considéré comme une valeur précise. En tant que telle, si vous n'avez pas besoin de mesurer des temps séparés par de simples nanosecondes, cette méthode est suffisante même si la valeur renvoyée résultante est négative. Cependant, si vous avez besoin d'une précision plus élevée, ils semblent vous recommander d'utiliser JAVA RTS.
Donc, pour répondre à votre question ... aucun nanoTime () n'est pas inutile ... ce n'est tout simplement pas la méthode la plus prudente à utiliser dans toutes les situations.
la source
-100
,-99
,-98
(Valeurs évidemment beaucoup plus importantes dans la pratique). Ils vont dans la bonne direction (en augmentant), il n'y a donc pas de problème ici.Pas besoin de débattre, utilisez simplement la source. Ici, SE 6 pour Linux, faites vos propres conclusions:
la source
Depuis Java 7, la
System.nanoTime()
sécurité est garantie par la spécification JDK.System.nanoTime()
Javadoc indique clairement que toutes les invocations observées dans une JVM (c'est-à-dire sur tous les threads) sont monotones:L'implémentation JVM / JDK est responsable de l'aplanissement des incohérences qui pourraient être observées lorsque les utilitaires du système d'exploitation sous-jacents sont appelés (par exemple ceux mentionnés dans la réponse de Tom Anderson ).
La majorité des autres anciennes réponses à cette question (écrites en 2009-2012) expriment un FUD qui était probablement pertinent pour Java 5 ou Java 6 mais qui n'est plus pertinent pour les versions modernes de Java.
Il convient cependant de mentionner que malgré
nanoTime()
la sécurité des garanties JDK , il y a eu plusieurs bogues dans OpenJDK qui l'empêchent de respecter cette garantie sur certaines plates-formes ou dans certaines circonstances (par exemple JDK-8040140 , JDK-8184271 ). Il n'y a pas de bogue ouvert (connu) dans OpenJDKnanoTime()
pour le moment, mais la découverte d'un nouveau bogue ou une régression dans une nouvelle version d'OpenJDK ne devrait choquer personne.Dans cet esprit, le code qui utilise
nanoTime()
pour le blocage temporisé, l'attente d'intervalle, les délais d'attente, etc. devrait de préférence traiter les différences de temps négatives (délais d'attente) comme des zéros plutôt que de lever des exceptions. Cette pratique est également préférable , car il est compatible avec le comportement de toutes les méthodes chronométrées d'attente dans toutes les classesjava.util.concurrent.*
, par exempleSemaphore.tryAcquire()
,Lock.tryLock()
,BlockingQueue.poll()
, etc.Néanmoins, il
nanoTime()
faut toujours préférer pour mettre en œuvre le blocage temporisé, l'attente d'intervalle, les délais d'attente, etc. àcurrentTimeMillis()
parce que ce dernier est sujet au phénomène de «retour en arrière» (par exemple en raison de la correction de l'heure du serveur), c'estcurrentTimeMillis()
-à- dire qu'il n'est pas adapté à la mesure des intervalles de temps du tout. Voir cette réponse pour plus d'informations.Au lieu d'utiliser
nanoTime()
directement pour les mesures de temps d'exécution du code, des cadres d'analyse comparative et des profileurs spécialisés devraient de préférence être utilisés, par exemple JMH et async-profiler en mode de profilage d'horloge murale .la source
Avertissement: je suis le développeur de cette bibliothèque
Vous aimerez peut-être mieux ceci:
http://juliusdavies.ca/nanotime/
Mais il copie un fichier DLL ou Unix .so (objet partagé) dans le répertoire personnel de l'utilisateur actuel afin qu'il puisse appeler JNI.
Certaines informations générales sont sur mon site à:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html
la source
Linux corrige les écarts entre les processeurs, mais pas Windows. Je vous suggère de supposer que System.nanoTime () n'est précis qu'à environ 1 micro-seconde. Un moyen simple d'obtenir une durée plus longue est d'appeler foo () 1000 fois ou plus et de diviser le temps par 1000.
la source
Absolument pas inutile. Les amateurs de chronométrage soulignent correctement le problème multicœur, mais dans les applications de mots réels, il est souvent radicalement meilleur que currentTimeMillis ().
Lors du calcul des positions graphiques dans le cadre, les actualisations nanoTime () permettent un mouvement BEAUCOUP plus fluide dans mon programme.
Et je ne teste que sur des machines multicœurs.
la source
J'ai vu un temps écoulé négatif rapporté à l'aide de System.nanoTime (). Pour être clair, le code en question est:
et la variable «elapsedNanos» avait une valeur négative. (Je suis certain que l'appel intermédiaire a également pris moins de 293 ans, ce qui est le point de débordement pour les nanos stockés dans les longs :)
Cela s'est produit avec un matériel IBM v1.5 JRE 64 bits sur IBM P690 (multicœur) exécutant AIX. Je n'ai vu cette erreur se produire qu'une seule fois, elle semble donc extrêmement rare. Je ne connais pas la cause - est-ce un problème spécifique au matériel, un défaut JVM - je ne sais pas. Je ne connais pas non plus les implications pour la précision de nanoTime () en général.
Pour répondre à la question initiale, je ne pense pas que nanoTime soit inutile - il fournit un timing inférieur à la milliseconde, mais il existe un risque réel (pas seulement théorique) qu'il soit inexact que vous devez prendre en compte.
la source
Cela ne semble pas être un problème sur un Core 2 Duo exécutant Windows XP et JRE 1.5.0_06.
Dans un test avec trois threads, je ne vois pas System.nanoTime () revenir en arrière. Les processeurs sont tous les deux occupés et les threads s'endorment parfois pour provoquer des mouvements de threads.
[EDIT] Je suppose que cela n'arrive que sur des processeurs physiquement séparés, c'est-à-dire que les compteurs sont synchronisés pour plusieurs cœurs sur le même die.
la source
Non, ce n'est pas ... Cela dépend juste de votre CPU, vérifiez le Minuteur d'événements de haute précision pour savoir comment / pourquoi les choses sont traitées différemment en fonction du CPU.
En gros, lisez la source de votre Java et vérifiez ce que votre version fait avec la fonction, et si cela fonctionne avec le processeur sur lequel vous l'exécuterez.
IBM vous suggère même de l' utiliser pour l'analyse comparative des performances (un article de 2008, mais mis à jour).
la source
Je fais un lien avec ce qui est essentiellement la même discussion où Peter Lawrey fournit une bonne réponse. Pourquoi j'obtiens un temps écoulé négatif en utilisant System.nanoTime ()?
Beaucoup de gens ont mentionné que dans Java System.nanoTime () pouvait renvoyer un temps négatif. Je m'excuse de répéter ce que d'autres personnes ont déjà dit.
Ce serait cool si System.nanoTime () retournait coreID là où il s'exécutait.
la source
Java est multiplateforme et nanoTime dépend de la plate-forme. Si vous utilisez Java - quand n'utilisez pas nanoTime. J'ai trouvé de vrais bugs dans différentes implémentations jvm avec cette fonction.
la source
La documentation Java 5 recommande également d'utiliser cette méthode dans le même but.
Doc API Java 5
la source
En outre,
System.currentTimeMillies()
change lorsque vous modifiez l'horloge de votre système, alors que ceSystem.nanoTime()
n'est pas le cas, ce dernier est donc plus sûr pour mesurer les durées.la source
nanoTime
est extrêmement incertain pour le timing. Je l'ai essayé sur mes algorithmes de test de primalité de base et il a donné des réponses qui étaient littéralement à une seconde d'intervalle pour la même entrée. N'utilisez pas cette méthode ridicule. J'ai besoin de quelque chose qui soit plus précis et précis que le temps millisime, mais pas aussi mauvais quenanoTime
.la source