Недавно я создавал приложение для регистрации ошибок и искал способ точной отметки времени для входящих данных. Когда я говорю точно, я имею в виду, что каждая временная метка должна быть точной относительно друг друга (нет необходимости синхронизировать с атомными часами или чем-то в этом роде).
Я использовал datetime.now () в качестве первого удара, но это не идеально:
>>> for i in range(0,1000):
... datetime.datetime.now()
...
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 562000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 578000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 609000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 609000)
datetime.datetime(2008, 10, 1, 13, 17, 27, 609000)
etc.
Изменения между часами для первой секунды образцов выглядят следующим образом:
uSecs difference
562000
578000 16000
609000 31000
625000 16000
640000 15000
656000 16000
687000 31000
703000 16000
718000 15000
750000 32000
765000 15000
781000 16000
796000 15000
828000 32000
843000 15000
859000 16000
890000 31000
906000 16000
921000 15000
937000 16000
968000 31000
984000 16000
Таким образом, похоже, что данные таймера обновляются только каждые ~ 15-32 мс на моей машине. Проблема возникает, когда мы приступаем к анализу данных, потому что сортировка по чему-то другому, кроме метки времени, а затем повторная сортировка по метке времени может оставить данные в неправильном порядке (в хронологическом порядке). Было бы неплохо иметь метки времени с точностью до такой степени, чтобы любой вызов генератора меток времени давал уникальную метку времени.
Я рассматривал некоторые методы, включающие использование вызова time.clock (), добавленного в начальную дату и время, но был бы признателен за решение, которое будет точно работать между потоками на одной машине. Любые предложения будут с благодарностью приняты.
Зачем вы строите свою собственную систему ведения лесозаготовок? Их уже много, и временные метки - это решенная проблема (с определенной степенью точности). В том маловероятном случае, если у вас есть вариант использования, который не решает никакая существующая структура ведения журнала, можете ли вы выбрать ближайший, поднять вопрос и отправить ему свой код?
Потому что ~ 8,5 лет назад (когда я опубликовал это) возможности были несколько более ограниченными. Я не создавал фреймворк для регистрации ошибок, я писал что-то для получения данных UDP и информации журнала от этого. Если бы была доступна библиотека (и я ее нашел), я бы был полностью открыт для ее использования ;-)






time.clock () измеряет только время настенных часов в Windows. В других системах time.clock () фактически измеряет время процессора. В этих системах time.time () больше подходит для настенного времени, и у него такое же высокое разрешение, какое может поддерживать Python - настолько высокое, насколько может управлять ОС; обычно используется gettimeofday (3) (разрешение в микросекундах) или ftime (3) (разрешение в миллисекундах). Другие ограничения ОС фактически делают реальное разрешение намного выше этого. datetime.datetime.now () использует time.time (), поэтому напрямую time.time () не будет лучше.
Для записи: если я использую datetime.datetime.now () в цикле, я вижу разрешение примерно 1/10000 секунды. Глядя на свои данные, вы получаете гораздо более грубое разрешение, чем это. Я не уверен, что Python как таковой может что-то сделать, хотя вы можете убедить ОС работать лучше другими способами.
Кажется, я помню, что в Windows time.clock () на самом деле (немного) более точен, чем time.time (), но он измеряет настенные часы с момента первого вызова time.clock (), поэтому вы должны не забыть `` инициализировать это первое.
Действительно, вот что это выглядит в Debian / Linux: datetime.datetime (2008, 10, 1, 17, 11, 31, 875190) datetime.datetime (2008, 10, 1, 17, 11, 31, 875199) datetime. datetime (2008, 10, 1, 17, 11, 31, 875207)
Я могу подтвердить, что часы действительно более точны на всех машинах с Windows, на которых я их пробовал.
Вот ветка о точности синхронизации Python:
Python - time.clock () vs. time.time () - точность?
Да, я уже видел это, но они относятся к запуску процесса или вызову часов, а не к абсолютному времени.
Вы вряд ли получите достаточно детальный контроль, чтобы полностью исключить возможность повторяющихся меток времени - вам потребуется разрешение меньше, чем время, необходимое для создания объекта datetime. Есть несколько других подходов, которые вы можете использовать, чтобы справиться с этим:
Смирись с этим. Оставьте свои временные метки неуникальными как есть, но положитесь на стабильность сортировки python, чтобы справиться с проблемами переупорядочения. Сортировка по метке времени первый, тогда что-то еще сохранит порядок меток времени - вам просто нужно быть осторожным, чтобы всегда начинать с упорядоченного списка меток времени каждый раз, а не выполнять несколько сортировок в одном и том же списке.
Добавьте свое собственное значение, чтобы добиться уникальности. Например. включите увеличивающееся целочисленное значение как часть ключа или добавьте такое значение только в том случае, если временные метки различны. Например.
Следующее будет гарантировать уникальные значения меток времени:
class TimeStamper(object):
def __init__(self):
self.lock = threading.Lock()
self.prev = None
self.count = 0
def getTimestamp(self):
with self.lock:
ts = str(datetime.now())
if ts == self.prev:
ts +='.%04d' % self.count
self.count += 1
else:
self.prev = ts
self.count = 1
return ts
Однако для нескольких процессов (а не потоков) это становится немного сложнее.
Я понимаю, что это немного придирчиво, но вы имеете в виду «строго возрастающее целое число», а не «монотонно возрастающее целое число». Монотонно увеличивающийся набор означает, что он никогда не уменьшается, но может иметь равные значения.
Все придирки с благодарностью приняты. Вы абсолютно правы - я исправил корявые формулировки.
"отметки времени должны быть точными относительно друг друга"
Почему время? Почему не порядковый номер? Если это какой-либо клиент клиент-серверного приложения, сетевая задержка делает временные метки случайными.
Вы сопоставляете какой-то внешний источник информации? Скажите лог в другом приложении? Опять же, если есть сеть, те времена не будут слишком близкими.
Если вы должны сопоставить вещи между отдельными приложениями, рассмотрите возможность передачи GUID, чтобы оба приложения регистрировали значение GUID. Тогда вы можете быть абсолютно уверены, что они совпадают, независимо от разницы во времени.
Если вы хотите, чтобы порядок относительный был в точности правильным, возможно, вашему регистратору достаточно присвоить порядковый номер каждому сообщению в том порядке, в котором они были получены.
Мне нужны были отметки времени, потому что мне нужно знать, когда данные собираются, и видеть, когда в производимых данных есть пробелы.
Если ваше решение зависит от точности часов, вам нужно будет найти ОС, которая гарантирует, что ваш процесс всегда будет первым, что происходит при поступлении собранных данных. В противном случае планирование ОС будет мешать этому.
Спасибо всем за ваш вклад - все они были очень полезны. Ответ Брайана кажется наиболее близким к тому, с чем я в конечном итоге пошел (т.е. справился с этим, но использовал своего рода уникальный идентификатор - см. Ниже), поэтому я принял его ответ. Мне удалось объединить все различные приемники данных в один поток, где теперь выполняется временная метка с использованием моего нового класса AccurrateTimeStamp. То, что я сделал, работает, пока метка времени - это первое, что нужно использовать в часах.
Как утверждает С.Лотт, без ОС реального времени они никогда не будут абсолютно идеальными. Я действительно хотел только то, что позволяло бы мне видеть относительно каждого входящего блока данных, когда что-то было получено, поэтому то, что у меня есть ниже, будет работать хорошо.
Еще раз спасибо всем!
import time
class AccurateTimeStamp():
"""
A simple class to provide a very accurate means of time stamping some data
"""
# Do the class-wide initial time stamp to synchronise calls to
# time.clock() to a single time stamp
initialTimeStamp = time.time()+ time.clock()
def __init__(self):
"""
Constructor for the AccurateTimeStamp class.
This makes a stamp based on the current time which should be more
accurate than anything you can get out of time.time().
NOTE: This time stamp will only work if nothing has called clock() in
this instance of the Python interpreter.
"""
# Get the time since the first of call to time.clock()
offset = time.clock()
# Get the current (accurate) time
currentTime = AccurateTimeStamp.initialTimeStamp+offset
# Split the time into whole seconds and the portion after the fraction
self.accurateSeconds = int(currentTime)
self.accuratePastSecond = currentTime - self.accurateSeconds
def GetAccurateTimeStampString(timestamp):
"""
Function to produce a timestamp of the form "13:48:01.87123" representing
the time stamp 'timestamp'
"""
# Get a struct_time representing the number of whole seconds since the
# epoch that we can use to format the time stamp
wholeSecondsInTimeStamp = time.localtime(timestamp.accurateSeconds)
# Convert the whole seconds and whatever fraction of a second comes after
# into a couple of strings
wholeSecondsString = time.strftime("%H:%M:%S", wholeSecondsInTimeStamp)
fractionAfterSecondString = str(int(timestamp.accuratePastSecond*1000000))
# Return our shiny new accurate time stamp
return wholeSecondsString+"."+fractionAfterSecondString
if __name__ == '__main__':
for i in range(0,500):
timestamp = AccurateTimeStamp()
print GetAccurateTimeStampString(timestamp)
Я хотел поблагодарить Дж. Кейджа за этот последний пост.
Для моей работы очень важна «разумная» синхронизация событий между процессами и платформами. Очевидно, что есть много мест, где что-то может пойти не так (дрейф часов, переключение контекста и т. д.), Однако это точное временное решение, я думаю, поможет гарантировать, что записанные временные метки достаточно точны, чтобы увидеть другие источники ошибок. .
Тем не менее, мне интересно несколько деталей, которые объясняются в Когда микросекунды имеют значение. Например, я думаю, что time.clock () в конечном итоге завершится. Я думаю, что для того, чтобы это сработало для длительного процесса, вам, возможно, придется с этим справиться.
Прошло несколько лет с тех пор, как этот вопрос был задан и дан ответ, и это было решено, по крайней мере, для CPython в Windows. Используя приведенный ниже сценарий как на 64-битной Win7, так и на Windows Server 2008 R2, я получил одинаковые результаты:
datetime.now() дает разрешение 1 мс и джиттер менее 1 мсtime.clock() дает разрешение лучше 1 мкс и джиттер намного меньше 1 мсСценарий:
import time
import datetime
t1_0 = time.clock()
t2_0 = datetime.datetime.now()
with open('output.csv', 'w') as f:
for i in xrange(100000):
t1 = time.clock()
t2 = datetime.datetime.now()
td1 = t1-t1_0
td2 = (t2-t2_0).total_seconds()
f.write('%.6f,%.6f\n' % (td1, td2))
Визуализированные результаты:

Если вам нужны временные метки микросекунды-разрешающая способность (НЕ точность) в Python, в Окна, вы можете использовать таймер Windows QPC, как показано в моем ответе здесь: Как получить временные метки с разрешением в миллисекундах и микросекундах в Python. Я еще не уверен, как это сделать в Linux, поэтому, если кто-нибудь знает, прокомментируйте или ответьте по ссылке выше.
Я только что опубликовал новый ответ, по крайней мере, в Окна, используя Python, вы можете получить временные метки субмикросекунды-разрешающая способность (НЕ точность), используя часы Windows QPC, как я демонстрирую в коде, связанном в моем ответе.