Высокоточные часы в 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()