Точная отметка времени в журнале Python

Недавно я создавал приложение для регистрации ошибок и искал способ точной отметки времени для входящих данных. Когда я говорю точно, я имею в виду, что каждая временная метка должна быть точной относительно друг друга (нет необходимости синхронизировать с атомными часами или чем-то в этом роде).

Я использовал 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 (), добавленного в начальную дату и время, но был бы признателен за решение, которое будет точно работать между потоками на одной машине. Любые предложения будут с благодарностью приняты.

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

Gabriel Staples 09.08.2016 05:01

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

smci 10.07.2017 18:17

Потому что ~ 8,5 лет назад (когда я опубликовал это) возможности были несколько более ограниченными. Я не создавал фреймворк для регистрации ошибок, я писал что-то для получения данных UDP и информации журнала от этого. Если бы была доступна библиотека (и я ее нашел), я бы был полностью открыт для ее использования ;-)

Jon Cage 13.07.2017 18:43
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
12
3
9 477
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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)

bortzmeyer 01.10.2008 19:13

Я могу подтвердить, что часы действительно более точны на всех машинах с Windows, на которых я их пробовал.

Jon Cage 01.10.2008 23:21

Вот ветка о точности синхронизации Python:

Python - time.clock () vs. time.time () - точность?

Да, я уже видел это, но они относятся к запуску процесса или вызову часов, а не к абсолютному времени.

Jon Cage 01.10.2008 19:04
Ответ принят как подходящий

Вы вряд ли получите достаточно детальный контроль, чтобы полностью исключить возможность повторяющихся меток времени - вам потребуется разрешение меньше, чем время, необходимое для создания объекта datetime. Есть несколько других подходов, которые вы можете использовать, чтобы справиться с этим:

  1. Смирись с этим. Оставьте свои временные метки неуникальными как есть, но положитесь на стабильность сортировки python, чтобы справиться с проблемами переупорядочения. Сортировка по метке времени первый, тогда что-то еще сохранит порядок меток времени - вам просто нужно быть осторожным, чтобы всегда начинать с упорядоченного списка меток времени каждый раз, а не выполнять несколько сортировок в одном и том же списке.

  2. Добавьте свое собственное значение, чтобы добиться уникальности. Например. включите увеличивающееся целочисленное значение как часть ключа или добавьте такое значение только в том случае, если временные метки различны. Например.

Следующее будет гарантировать уникальные значения меток времени:

    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

Однако для нескольких процессов (а не потоков) это становится немного сложнее.

Я понимаю, что это немного придирчиво, но вы имеете в виду «строго возрастающее целое число», а не «монотонно возрастающее целое число». Монотонно увеличивающийся набор означает, что он никогда не уменьшается, но может иметь равные значения.

Tony Arkles 12.11.2008 19:12

Все придирки с благодарностью приняты. Вы абсолютно правы - я исправил корявые формулировки.

Brian 13.11.2008 01:37

"отметки времени должны быть точными относительно друг друга"

Почему время? Почему не порядковый номер? Если это какой-либо клиент клиент-серверного приложения, сетевая задержка делает временные метки случайными.

Вы сопоставляете какой-то внешний источник информации? Скажите лог в другом приложении? Опять же, если есть сеть, те времена не будут слишком близкими.

Если вы должны сопоставить вещи между отдельными приложениями, рассмотрите возможность передачи GUID, чтобы оба приложения регистрировали значение GUID. Тогда вы можете быть абсолютно уверены, что они совпадают, независимо от разницы во времени.

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

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

Jon Cage 01.10.2008 23:24

Если ваше решение зависит от точности часов, вам нужно будет найти ОС, которая гарантирует, что ваш процесс всегда будет первым, что происходит при поступлении собранных данных. В противном случае планирование ОС будет мешать этому.

S.Lott 01.10.2008 23:31

Спасибо всем за ваш вклад - все они были очень полезны. Ответ Брайана кажется наиболее близким к тому, с чем я в конечном итоге пошел (т.е. справился с этим, но использовал своего рода уникальный идентификатор - см. Ниже), поэтому я принял его ответ. Мне удалось объединить все различные приемники данных в один поток, где теперь выполняется временная метка с использованием моего нового класса 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, поэтому, если кто-нибудь знает, прокомментируйте или ответьте по ссылке выше.

Другие вопросы по теме