Проблема не только в том, что таймер сна python является неточным, но и в том, что каждая часть цикла требует некоторого времени.
Ваш исходный код имеет время выполнения ~ 1.9528656005859375 в моей системе.
Если я только запускаю эту часть вашего кода без сна:
for i in range(100000):
dt += datetime.timedelta(microseconds=1)
Тогда требуемое время для этого цикла уже ~ 0,45999741554260254.
Если я только запускаю
for i in range(1000000):
pause.milliseconds(0)
Тогда время выполнения кода ~ 0,5583224296569824.
Использование всегда одной и той же даты:
dt = datetime.datetime.now()
for i in range(1000000):
pause.until(dt)
Результат выполнения ~ 1,326077938079834
Если вы сделаете то же самое с отметкой времени:
dt = datetime.datetime.now()
ts = dt.timestamp()
for i in range(1000000):
pause.until(ts)
Тогда время выполнения изменится на ~ 0.36722803115844727
И если вы увеличите отметку времени на одну микросекунду:
dt = datetime.datetime.now()
ts = dt.timestamp()
for i in range(1000000):
ts += 0.000001
pause.until(ts)
Тогда вы получите время выполнения ~ 0,9536933898925781
То, что оно меньше 1, связано с неточностями с плавающей запятой, добавив print(ts-dt.timestamp())
после того, как цикл покажет ~ 0,95367431640625, так что продолжительность самой паузыправильно, бно ts += 0.000001
накапливает ошибку.
Вы получите лучший результат, если посчитаете количество итераций и добавите iterationCount/1000000
к времени начала:
dt = datetime.datetime.now()
ts = dt.timestamp()
for i in range(1000000):
pause.until(ts+i/1000000)
И этоприведет к ~ 1.000023365020752
Так что в моем случае pause
сам по себе уже позволит точность менее 1 микросекунды.Проблема на самом деле в части datetime
, которая требуется как для datetime.timedelta
, так и для sleep_until
.
. Поэтому, если вы хотите иметь точность в микросекундах, вам нужно искать библиотеку времени, которая работает лучше, чемdatetime
.