web-dev-qa-db-fra.com

Horloge haute précision en Python

Existe-t-il un moyen de mesurer le temps avec une haute précision en Python, avec une précision supérieure à une seconde? Je doute qu'il y ait un moyen multiplateforme de le faire; Je suis intéressé par le temps de haute précision sous Unix, en particulier par Solaris sur une machine Sun SPARC.

timeit semble être capable de mesurer le temps avec une grande précision, mais plutôt que de mesurer la durée d'un extrait de code, j'aimerais accéder directement aux valeurs de temps. 

36
fuad

La fonction standard time.time() fournit une précision inférieure à la seconde, bien que cette précision varie en fonction de la plate-forme. Pour Linux et Mac, la précision est de +- 1 microseconde ou 0,001 milliseconde. Python sous Windows utilise la précision +- 16 millisecondes en raison de problèmes d'implémentation d'horloge dus aux interruptions de processus. Le module timeit peut fournir une résolution plus élevée si vous mesurez le temps d'exécution.

>>> import time
>>> time.time()        #return seconds from Epoch
1261367718.971009      

Python 3.7 introduit de nouvelles fonctions dans le module time qui offrent une résolution supérieure:

>>> import time
>>> time.time_ns()
1530228533161016309
>>> time.time_ns() / (10 ** 9) # convert to floating-point seconds
1530228544.0792289
41
daf

Python s'efforce d'utiliser la fonction de temps la plus précise pour que votre plate-forme implémente time.time()

/* Implement floattime() for various platforms */

static double
floattime(void)
{
    /* There are three ways to get the time:
      (1) gettimeofday() -- resolution in microseconds
      (2) ftime() -- resolution in milliseconds
      (3) time() -- resolution in seconds
      In all cases the return value is a float in seconds.
      Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
      fail, so we fall back on ftime() or time().
      Note: clock resolution does not imply clock accuracy! */
#ifdef HAVE_GETTIMEOFDAY
    {
        struct timeval t;
#ifdef GETTIMEOFDAY_NO_TZ
        if (gettimeofday(&t) == 0)
            return (double)t.tv_sec + t.tv_usec*0.000001;
#else /* !GETTIMEOFDAY_NO_TZ */
        if (gettimeofday(&t, (struct timezone *)NULL) == 0)
            return (double)t.tv_sec + t.tv_usec*0.000001;
#endif /* !GETTIMEOFDAY_NO_TZ */
    }

#endif /* !HAVE_GETTIMEOFDAY */
    {
#if defined(HAVE_FTIME)
        struct timeb t;
        ftime(&t);
        return (double)t.time + (double)t.millitm * (double)0.001;
#else /* !HAVE_FTIME */
        time_t secs;
        time(&secs);
        return (double)secs;
#endif /* !HAVE_FTIME */
    }
}

(from http://svn.python.org/view/python/trunk/Modules/timemodule.c?revision=81756&view=markup )

22
Joe Koberg

Le message de David tentait de montrer quelle était la résolution de l'horloge sous Windows. Sa sortie m'a troublé, alors j'ai écrit un code qui montre que time.time() sur mon ordinateur portable Windows 8 x64 a une résolution de 1 ms:

# measure the smallest time delta by spinning until the time changes
def measure():
    t0 = time.time()
    t1 = t0
    while t1 == t0:
        t1 = time.time()
    return (t0, t1, t1-t0)

samples = [measure() for i in range(10)]

for s in samples:
    print s

Quelles sorties:

(1390455900.085, 1390455900.086, 0.0009999275207519531)
(1390455900.086, 1390455900.087, 0.0009999275207519531)
(1390455900.087, 1390455900.088, 0.0010001659393310547)
(1390455900.088, 1390455900.089, 0.0009999275207519531)
(1390455900.089, 1390455900.09, 0.0009999275207519531)
(1390455900.09, 1390455900.091, 0.0010001659393310547)
(1390455900.091, 1390455900.092, 0.0009999275207519531)
(1390455900.092, 1390455900.093, 0.0009999275207519531)
(1390455900.093, 1390455900.094, 0.0010001659393310547)
(1390455900.094, 1390455900.095, 0.0009999275207519531)

Et un moyen de faire une moyenne de 1000 échantillons du delta:

reduce( lambda a,b:a+b, [measure()[2] for i in range(1000)], 0.0) / 1000.0

Quelle sortie sur deux exécutions consécutives:

0.001
0.0010009999275207519

Donc, time.time() sur mon Windows 8 x64 a une résolution de 1 ms.

Une exécution similaire sur time.clock() renvoie une résolution de 0,4 microsecondes: 

def measure_clock():
    t0 = time.clock()
    t1 = time.clock()
    while t1 == t0:
        t1 = time.clock()
    return (t0, t1, t1-t0)

reduce( lambda a,b:a+b, [measure_clock()[2] for i in range(1000000)] )/1000000.0

Résultats:

4.3571334791658954e-07

Quel est ~ 0.4e-06

Une chose intéressante à propos de time.clock() est qu’elle renvoie le temps écoulé depuis le premier appel de la méthode. Par conséquent, si vous voulez un temps de résolution du mur d’une résolution de la microseconde, procédez comme suit:

class HighPrecisionWallTime():
    def __init__(self,):
        self._wall_time_0 = time.time()
        self._clock_0 = time.clock()

    def sample(self,):
        dc = time.clock()-self._clock_0
        return self._wall_time_0 + dc

(qui dériverait probablement après un certain temps, mais vous pouvez le corriger de temps en temps, par exemple dc > 3600 le corrigerait toutes les heures)

19
cod3monk3y

Vous pouvez également utiliser time.clock (). Il compte le temps utilisé par le processus sous Unix et le temps écoulé depuis le premier appel sous Windows. C'est plus précis que time.time ().

C'est la fonction généralement utilisée pour mesurer les performances.

Il suffit d'appeler 

import time
t_ = time.clock()
#Your code here
print 'Time in function', time.clock() - t_

EDITED: Ups, je manque la question car vous voulez savoir exactement le temps, pas le temps passé ... 

13
Khelben

Si Python 3 est une option, vous avez deux choix:

  • time.perf_counter qui utilise toujours l'horloge la plus précise sur votre plate-forme. Cela inclut le temps passé en dehors du processus.
  • time.process_time qui renvoie le temps processeur. Cela n'inclut pas _ le temps passé en dehors du processus.

La différence entre les deux peut être montrée avec:

from time import (
    process_time,
    perf_counter,
    sleep,
)

print(process_time())
sleep(1)
print(process_time())

print(perf_counter())
sleep(1)
print(perf_counter())

Quelles sorties:

0.03125
0.03125
2.560001310720671e-07
1.0005455362793145
7
ereOn

time.clock() a 13 points décimaux sous Windows mais seulement deux sous Linux .time.time() en a 17 décimales sous Linux et 16 sous Windows mais la précision réelle est différente.

Je ne suis pas d'accord avec la documentation selon laquelle time.clock() devrait être utilisé pour l'analyse comparative sous Unix/Linux. Ce n'est pas assez précis, donc la minuterie à utiliser dépend du système d'exploitation.

Sous Linux, la résolution temporelle est élevée dans time.time():

>>> time.time(), time.time()
(1281384913.4374139, 1281384913.4374161)

Sous Windows, toutefois, la fonction heure semble utiliser le dernier numéro appelé:

>>> time.time()-int(time.time()), time.time()-int(time.time()), time.time()-time.time()
(0.9570000171661377, 0.9570000171661377, 0.0)

Même si j'écris les appels sur des lignes différentes de Windows, la valeur est toujours la même, ce qui réduit la précision réelle.

Ainsi, dans les mesures sérieuses, une vérification de la plate-forme (import platform, platform.system()) doit être effectuée afin de déterminer s'il convient d'utiliser time.clock() ou time.time().

(Testé sous Windows 7 et Ubuntu 9.10 avec Python 2.6 et 3.1)

4
David

Le commentaire laissé par tiho le 27 mars 14 à 17:21 mérite d'être sa propre réponse:

Afin d'éviter le code spécifique à la plate-forme, utilisez timeit.default_timer ()

2
Justin

J'ai constaté que la résolution de time.time () est différente entre les versions Windows 10 Professional et Education.

Sur un ordinateur Windows 10 Professionnel, la résolution est de 1 ms. Sur un ordinateur Windows 10 Education, la résolution est de 16 ms.

Heureusement, il existe un outil qui augmente la résolution temporelle de Python sous Windows: https://vvvv.org/contribution/windows-system-timer-tool

Avec cet outil, j'ai pu atteindre une résolution de 1 ms quelle que soit la version de Windows. Vous devrez le garder en marche tout en exécutant vos codes Python.

1
dbdq

Pour ceux qui sont bloqués sur Windows (version> = server 2012 ou win 8) et python 2.7,

import ctypes

class FILETIME(ctypes.Structure):
    _fields_ = [("dwLowDateTime", ctypes.c_uint),
                ("dwHighDateTime", ctypes.c_uint)]

def time():
    """Accurate version of time.time() for windows, return UTC time in term of seconds since 01/01/1601
"""
    file_time = FILETIME()
    ctypes.windll.kernel32.GetSystemTimePreciseAsFileTime(ctypes.byref(file_time))
    return (file_time.dwLowDateTime + (file_time.dwHighDateTime << 32)) / 1.0e7

Fonction GetSystemTimePreciseAsFileTime

0
CyberSnoopy