Подтвердить что ты не робот

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

4b9b3361

Ответ 1

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

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

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

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

    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

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

Ответ 2

time.clock() измеряет только время работы в Windows. В других системах время .clock() фактически измеряет время CPU. В этих системах time.time() больше подходит для времени настенного времени, и он имеет такое высокое разрешение, которое может управлять Python, - что выше, чем может управлять ОС; обычно используя gettimeofday (3) (разрешение в микросекундах) или ftime (3) (разрешение в миллисекундах). Другие ограничения ОС фактически делают реальное разрешение намного выше, чем это. datetime.datetime.now() использует time.time(), поэтому time.time() напрямую не будет лучше.

Для записи, если я использую datetime.datetime.now() в цикле, я вижу примерно 1/10000 секундное разрешение. От взгляда на ваши данные у вас есть намного, гораздо более грубое разрешение, чем это. Я не уверен, что что-то может сделать Python как таковой, хотя вы можете убедить ОС сделать лучше с помощью других средств.

Кажется, я вспоминаю, что в Windows время .clock() на самом деле (немного) точнее, чем time.time(), но оно измеряет стену с момента первого вызова time.clock(), поэтому вам нужно помнить сначала инициализировать его.

Ответ 3

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

Как указывает S.Lott, без ОС реального времени они никогда не будут абсолютно идеальными. Я действительно хотел только что-то, что позволило бы мне видеть по отношению к каждому входящему фрагменту данных, когда что-то получалось, а то, что у меня было ниже, будет хорошо работать.

Еще раз спасибо всем!

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)

Ответ 4

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

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

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

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

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

Ответ 6

Несколько лет назад, когда был задан вопрос и ответили, и это было рассмотрено, по крайней мере, для CPython в Windows. Используя script ниже как на Win7 64bit, так и на Windows Server 2008 R2, я получил те же результаты:

  • datetime.now() дает разрешение 1 мс и дрожание меньше 1 мс
  • time.clock() дает разрешение лучше, чем 1us, и дрожание намного меньше, чем 1 мс

script:

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

Результаты визуализируются: enter image description here

Ответ 7

Я хотел поблагодарить Дж. Кейджа за этот последний пост.

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

Тем не менее, есть несколько деталей, о которых мне интересно, об этом объясняется в Когда MicroSeconds Matter. Например, я думаю, что time.clock() в конечном итоге будет завершен. Я думаю, для этого, чтобы работать в течение длительного времени, вам, возможно, придется справиться с этим.

Ответ 8

Если вы хотите использовать отметки времени с микросекундным разрешением (NOT precision) в Python, в Windows вы можете использовать таймер QPS для Windows, как показано в моем ответе здесь: Как получить миллисекунду и микросекунду -resolution timestamps в Python. Я не уверен, как это сделать в Linux, но если кто-нибудь знает, прокомментируйте или ответьте по ссылке выше.