Pergunta

Eu tenho vindo a construir um aplicativo de log de erro recentemente e foi após uma forma de timestamping com precisão os dados recebidos. Quando eu digo que quero dizer com precisão cada timestamp deve ser preciso em relação ao outro (não há necessidade de sincronização para um relógio atômico ou algo parecido).

Eu tenho usado datetime.now () como uma primeira tentativa, mas isso não é perfeito:

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

As mudanças entre relógios para o primeiro segundo de amostras parecido com este:

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

Portanto, parece que os dados de temporizador só é atualizada a cada ~ 15-32ms na minha máquina. O problema surge quando passamos a analisar os dados, porque a classificação por algo que não seja a hora e, em seguida, classificar por timestamp novamente pode deixar os dados na ordem errada (em ordem cronológica). Seria bom ter os carimbos de hora precisos a ponto de que qualquer chamada para o gerador de carimbo de tempo dá um timestamp único.

I tinha sido considerar alguns métodos que envolvem usando uma chamada time.clock () adicionada a uma data e hora de partida, mas iria apreciar uma solução que iria funcionar com precisão através de roscas na mesma máquina. Todas as sugestões serão muito gratamente recebidas.

Foi útil?

Solução

Você é improvável que se obtenha o controle suficientemente refinada que você pode eliminar completamente a possibilidade de timestamps duplicados - você precisa de resolução menor do que o tempo que leva para gerar um objeto de data e hora. Há um par de outras abordagens que você pode tomar para lidar com isso:

  1. lidar com isso. Deixe suas marcas de tempo não-exclusivo como elas são, mas dependem de sorte ser estável de python para lidar com problemas reordenação. Classificando em timestamp início , em seguida, outra coisa vai manter a ordenação timestamp - você apenas tem que ter o cuidado de sempre começar a partir do timestamp lista ordenada de cada vez, ao invés de fazer vários tipos na mesma lista.

  2. Anexe o seu próprio valor para impor exclusividade. Por exemplo. incluem um valor inteiro incrementando como parte da chave, ou de acréscimo valor tal apenas se marcas de tempo são diferentes. Por exemplo.

A seguir irá garantir os valores de timestamp únicas:

    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

Para vários processos (em vez de threads), ele fica um pouco mais complicado embora.

Outras dicas

time.clock () só mede o tempo wallclock no Windows. Em outros sistemas, time.clock () realmente mede CPU-time. Nesses sistemas time.time () é mais adequado para o tempo wallclock, e tem como alta resolução de um como Python pode gerenciar - que é tão alto quanto o sistema operacional pode gerenciar; geralmente usando gettimeofday (3) (resolução de microsegundos) ou ftime (3) (milissegundo resolução.) Outras restrições OS realmente fazer a resolução verdadeira muito maior do que isso. datetime.datetime.now () usa time.time (), então time.time () diretamente não será melhor.

Para o registro, se eu usar datetime.datetime.now () em um loop, eu vejo sobre uma segunda resolução 1/10000. De olhar para os seus dados, você tem muito, resolução grosseira muito do que isso. Eu não tenho certeza se há alguma coisa Python, como tal, pode fazer, embora você pode ser capaz de convencer o OS para fazer melhor através de outros meios.

Se bem me lembro que no Windows, time.clock () é na verdade (ligeiramente) mais preciso do que time.time (), mas ele mede wallclock desde a primeira chamada para time.clock (), então você tem que lembrar para 'initialize' pela primeira vez.

Obrigado a todos por suas contribuições - todos eles ser muito útil. A resposta de Brian parece mais próximo do que eu finalmente fui com (ou seja, lidar com isso, mas usar um tipo de identificador único - veja abaixo) para que eu tenha aceitado sua resposta. I conseguiu consolidar todos os vários receptores de dados em um único segmento que é onde o timestamping agora é feito usando meu novo AccurrateTimeStamp classe. O que eu fiz obras, desde que o carimbo de tempo é a primeira coisa a usar o relógio.

consagra como S. Lott, sem um sistema operacional em tempo real, que nunca vai ser absolutamente perfeito. Eu realmente só queria algo que me deixe ver em relação a cada bloco de entrada de dados, quando as coisas estavam sendo recebidos por isso que eu tenho a seguir irá funcionar bem.

Mais uma vez obrigado a todos!

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)

"timestamp deve ser preciso em relação ao outro"

Por tempo? Por que não um número de seqüência? Se é qualquer cliente de aplicação cliente-servidor, a latência da rede faz timestamps tipo de aleatório.

Você está combinando alguma fonte externa de informações? Digamos que um log em outro aplicativo? Mais uma vez, se há uma rede, naqueles tempos não será muito perto.

Se você deve combinar as coisas entre aplicativos separados, considere passando de GUID em torno de modo que ambos os aplicativos registrar o valor GUID. Então você pode ser absolutamente certo de que eles corresponderem, independentemente das diferenças de tempo.

Se você deseja que o relação para ser exatamente certo, talvez seja suficiente para o seu logger para atribuir um número sequencial para cada mensagem na ordem em que foram recebidos.

Aqui é uma discussão sobre a precisão de tempo Python:
Python - time.clock () vs. time.time () - precisão

Alguns anos passados ??desde que a pergunta foi feita e respondida, e isso tem sido tratado, pelo menos para CPython no Windows. Usando o script abaixo em ambos 64 bits Win7 e Windows Server 2008 R2, eu tenho os mesmos resultados:

  • datetime.now() dá uma resolução de 1ms e um jitter menor que 1ms
  • time.clock() dá uma resolução melhor que 1us e uma instabilidade muito menor do que 1 ms

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

Os resultados visualizados: enter descrição da imagem aqui

Eu queria agradecer J. gaiola para este último post.

Para o meu trabalho, o tempo "razoável" de eventos em processos e plataformas é essencial. Existem, obviamente, muitos lugares onde as coisas podem ir torto (desvio de relógio, troca de contexto, etc.), no entanto esta solução timing exacto vai, penso eu, ajudar a garantir que os carimbos de hora gravadas são suficientemente precisos para ver as outras fontes de erro .

Dito isto, há um par de detalhes Eu me pergunto sobre o que são explicados em Quando microssegundos Matéria . Por exemplo, eu acho que time.clock () acabará por quebrar. Eu acho que para que isso funcione para um processo de longa duração, você pode ter que lidar com isso.

Se você quiser microsecond- Resolução (NÃO precisão) timestamps em Python, em Windows, você pode usar temporizador QPC do Windows, conforme demonstrado na minha resposta aqui: Como timestamps microssegundo de resolução de obter milissegundos e em Python . Eu não sei como fazer isso no Linux ainda, então se alguém souber, por favor, comentário ou resposta no link acima.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top