Точная отметка времени в журнале Python - PullRequest
12 голосов
/ 01 октября 2008

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

Я использовал 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 ]

12 голосов
/ 01 октября 2008

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 (), но он измеряет wallclock с момента первого вызова time.clock (), поэтому вы должны помнить сначала «инициализировать» его.

7 голосов
/ 01 октября 2008

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

  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

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

5 голосов
/ 02 октября 2008

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

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

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

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

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

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

2 голосов
/ 05 марта 2014

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

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

Сценарий:

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

2 голосов
/ 01 октября 2008

Вот нить о точности синхронизации Python:

Python - time.clock () против time.time () - точность?

0 голосов
/ 09 августа 2016

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

0 голосов
/ 12 ноября 2008

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

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

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

...