Высокоточные часы в Python

Есть ли способ измерить время с высокой точностью в Python - точнее, чем на одну секунду? Я сомневаюсь, что это кросс-платформенный способ сделать это; Мне интересна высокая точность времени в Unix, особенно Solaris, работающая на машине Sun SPARC.

timeit, похоже, способен к высокоточному измерению времени, но вместо того, чтобы измерять, сколько времени занимает фрагмент кода, я бы например, для прямого доступа к значениям времени.

Ответ 1

Стандартная time.time() обеспечивает точность до секунды, хотя эта точность зависит от платформы. Для Linux и Mac точность составляет +- 1 мкс или 0,001 мсек. Python в Windows использует точность +- 16 миллисекунд из-за проблем с реализацией часов из-за прерываний процесса. Модуль timeit может обеспечить более высокое разрешение, если вы измеряете время выполнения.

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

Python 3.7 представляет новые функции для модуля time которые обеспечивают более высокое разрешение:

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

Ответ 2

Python пытается использовать самую точную функцию времени для вашей платформы для реализации 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 */
    }
}

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

Ответ 3

Сообщение Дэвида пыталось показать, какое разрешение часов в Windows. Я был смущен его выходом, поэтому я написал код, который показывает, что time.time() на моем ноутбуке Windows 8 x64 имеет разрешение 1 мс:

# 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

Какие выходы:

(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)

И способ сделать 1000 выборок среднего значения delta:

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

Какой вывод на двух последовательных запусках:

0.001
0.0010009999275207519

Итак, time.time() на моей Windows 8 x64 имеет разрешение 1 мс.

Аналогичный прогон на time.clock() возвращает разрешение 0,4 микросекунды:

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

Возврат:

4.3571334791658954e-07

Что ~ ~ t29 >

Интересная вещь о time.clock() заключается в том, что она возвращает время с момента вызова метода, поэтому, если вы хотите настенное время на микросекундном разрешении, вы можете сделать что-то вроде этого:

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

(который, вероятно, будет дрейфовать через некоторое время, но вы можете исправить это иногда, например dc > 3600 будет исправлять его каждый час)

Ответ 4

Вы также можете использовать time.clock() Он подсчитывает время, используемое процессом в Unix, и время с момента его первого вызова в Windows. Это более точно, чем time.time().

Это обычно используемая функция для измерения производительности.

Просто позвоните

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

EDITED: Ups, я упускаю вопрос, поскольку вы хотите точно знать время, а не время, потраченное...

Ответ 5

Если Python 3 является опцией, у вас есть два варианта:

  • time.perf_counter, которые всегда используют самые точные часы на вашей платформе. Это включает время, потраченное вне процесса.
  • time.process_time, который возвращает время процессора. Он НЕ включает время, затраченное вне процесса.

Разницу между двумя можно показать с помощью:

from time import (
    process_time,
    perf_counter,
    sleep,
)

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

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

Какие выходы:

0.03125
0.03125
2.560001310720671e-07
1.0005455362793145

Ответ 6

time.clock() имеет 13 десятичных точек в Windows, но только два в Linux. time.time() имеет 17 десятичных знаков в Linux и 16 на Windows, но фактическая точность отличается.

Я не согласен с документацией, что time.clock() следует использовать для бенчмаркинга в Unix/Linux. Он недостаточно точен, поэтому используемый таймер зависит от операционной системы.

В Linux временное разрешение высоко в time.time():

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

В Windows, однако, функция времени использует последний вызываемый номер:

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

Даже если я пишу вызовы на разных строках в Windows, он все равно возвращает одно и то же значение, поэтому реальная точность ниже.

Таким образом, при серьезных измерениях необходимо проверить платформу (import platform, platform.system()), чтобы определить, следует ли использовать time.clock() или time.time().

(Протестировано в Windows 7 и Ubuntu 9.10 с помощью python 2.6 и 3.1)

Ответ 7

В Python 3.7 представлены 6 новых функций времени с разрешением наносекунд, например, вместо time.time() вы можете использовать time.time_ns():

import time
print(time.time())
# 1522915698.3436284
print(time.time_ns())
# 1522915698343660458

Эти 6 функций описаны в PEP 564:

time.clock_gettime_ns(clock_id)

time.clock_settime_ns(clock_id, time:int)

time.monotonic_ns()

time.perf_counter_ns()

time.process_time_ns()

time.time_ns()

Эти функции аналогичны версии без суффикса _ns, но возвращают количество наносекунд в виде Python int.

Ответ 8

Комментарий оставленный tiho 27-27 марта в 17:21, должен быть его собственным ответом:

Чтобы избежать кода, специфичного для платформы, используйте timeit.default_timer()

Ответ 9

Я заметил, что разрешение time.time() различается в версиях Windows 10 Professional и Education.

На компьютере с Windows 10 Professional разрешение составляет 1 мс. На компьютере с Windows 10 Education разрешение составляет 16 мс.

К счастью, есть инструмент, который увеличивает разрешение Python в Windows: https://vvvv.org/contribution/windows-system-timer-tool

С помощью этого инструмента я смог достичь разрешения 1 мс независимо от версии Windows. Вам нужно будет поддерживать его работу во время выполнения ваших кодов Python.

Ответ 10

Для тех, кто застрял на Windows (версия> = Server 2012 или Win 8) и 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

Функция GetSystemTimePreciseAsFileTime

Ответ 11

Оригинальный вопрос, специально заданный для Unix, но несколько ответов касались Windows, и, как следствие, вводящая в заблуждение информация о Windows. Разрешение таймера по умолчанию для окон составляет 15,6 мс, вы можете проверить здесь.

Используя слегка модифицированный скрипт из cod3monk3y, я могу показать, что разрешение таймера Windows по умолчанию составляет ~ 15 миллисекунд. Я использую инструмент, доступный здесь, чтобы изменить разрешение.

Автор сценария:

import time

# 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 t1-t0

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

for s in samples:
    print(f'time delta: {s:.4f} seconds') 

enter image description here

enter image description here

Эти результаты были собраны на Windows 10 Pro 64-разрядной версии Python 3.7 64-разрядной.

Ответ 12

В той же системе ОС win10, в которой используются "два разных подхода", существует приблизительная разница во времени "500 нс". Если вы заботитесь о такой точности, смотрите код ниже.

Модификации кода основаны на коде от пользователя cod3monk3y и Kevin S

ОС: python 3.7.3 (default, date, time) [MSC v.1915 64 bit (AMD64)]

def measure1(mean):
    for i in range(1, my_range+1):
        x = time.time()

        td = x- samples1[i-1][2]
        if i-1 == 0:
            td = 0
        td = f'{td:.6f}'
        samples1.append((i, td, x))
        mean += float(td)
        print (mean)
        sys.stdout.flush()
        time.sleep(0.001)

    mean = mean/my_range

    return mean

def measure2(nr):
    t0 = time.time()
    t1 = t0
    while t1 == t0:
        t1 = time.time()
    td = t1-t0
    td = f'{td:.6f}'
    return (nr, td, t1, t0)

samples1 = [(0, 0, 0)]
my_range = 10
mean1    = 0.0
mean2    = 0.0

mean1 = measure1(mean1)

for i in samples1: print (i)

print ('...\n\n')

samples2 = [measure2(i) for i in range(11)]

for s in samples2:
    #print(f'time delta: {s:.4f} seconds')
    mean2 += float(s[1])
    print (s)

mean2 = mean2/my_range

print ('\nMean1 : ' f'{mean1:.6f}')
print ('Mean2 : ' f'{mean2:.6f}')

Результаты меры1:

(0, 0, 0)
(1, '0.000000', 1562929696.617988)
(2, '0.002000', 1562929696.6199884)
(3, '0.001001', 1562929696.620989)
(4, '0.001001', 1562929696.62199)
(5, '0.001001', 1562929696.6229906)
(6, '0.001001', 1562929696.6239917)
(7, '0.001001', 1562929696.6249924)
(8, '0.001000', 1562929696.6259928)
(9, '0.001001', 1562929696.6269937)
(10, '0.001001', 1562929696.6279945)
...

Результат измерения2:

(0, '0.000500', 1562929696.6294951, 1562929696.6289947)
(1, '0.000501', 1562929696.6299958, 1562929696.6294951)
(2, '0.000500', 1562929696.6304958, 1562929696.6299958)
(3, '0.000500', 1562929696.6309962, 1562929696.6304958)
(4, '0.000500', 1562929696.6314962, 1562929696.6309962)
(5, '0.000500', 1562929696.6319966, 1562929696.6314962)
(6, '0.000500', 1562929696.632497, 1562929696.6319966)
(7, '0.000500', 1562929696.6329975, 1562929696.632497)
(8, '0.000500', 1562929696.633498, 1562929696.6329975)
(9, '0.000500', 1562929696.6339984, 1562929696.633498)
(10, '0.000500', 1562929696.6344984, 1562929696.6339984)

Конечный результат:

Среднее 1: 0,001001 # (функция измерения 1)

Mean2: 0,000550 # (функция measure2)

Ответ 13

def start(self):
    sec_arg = 10.0
    cptr = 0
    time_start = time.time()
    time_init = time.time()
    while True:
        cptr += 1
        time_start = time.time()
        time.sleep(((time_init + (sec_arg * cptr)) - time_start ))

        # AND YOUR CODE .......
        t00 = threading.Thread(name='thread_request', target=self.send_request, args=([]))
        t00.start()