12

我最近一直在构建一个错误记录应用程序,并且正在寻找一种准确地为传入数据加上时间戳的方法。当我准确地说时,我的意思是每个时间戳都应该相对于彼此准确(无需同步到原子钟或类似的东西)。

我一直在使用 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-32ms 更新一次。当我们开始分析数据时,问题就来了,因为按时间戳以外的东西排序,然后再次按时间戳排序可能会使数据处于错误的顺序(按时间顺序)。如果时间戳准确到任何对时间戳生成器的调用都会给出唯一的时间戳,那就太好了。

我一直在考虑一些涉及使用添加到起始日期时间的 time.clock() 调用的方法,但希望有一种解决方案可以在同一台机器上的线程间准确工作。任何建议将不胜感激。

4

8 回答 8

12

time.clock() 仅测量 Windows 上的挂钟时间。在其他系统上, time.clock() 实际上测量 CPU 时间。在那些系统上 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() 以来的挂钟,所以你必须记住“初始化” '它首先。

于 2008-10-01T12:54:25.957 回答
7

您不太可能获得足够细粒度的控制来完全消除重复时间戳的可能性 - 您需要的分辨率小于生成日期时间对象所需的时间。您可能会采取其他几种方法来处理它:

  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

对于多个进程(而不是线程),它变得有点棘手。

于 2008-10-01T13:55:57.153 回答
5

感谢大家的贡献——它们都非常有用。布赖恩的回答似乎最接近我最终的回答(即处理它,但使用一种唯一标识符 - 见下文),所以我接受了他的回答。我设法将所有各种数据接收器合并到一个线程中,现在使用我的新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)
于 2008-10-01T23:23:33.357 回答
3

“时间戳应该相互准确”

为什么是时间?为什么不是序列号?如果它是客户端-服务器应用程序的任何客户端,网络延迟会使时间戳变得随机。

您是否匹配了一些外部信息源?说另一个应用程序的日志?同样,如果有网络,那么这些时间不会太接近。

如果您必须在不同的应用程序之间进行匹配,请考虑传递 GUID,以便两个应用程序都记录 GUID 值。然后,您可以绝对确定它们匹配,无论时间差异如何。

如果您希望相对顺序完全正确,那么您的记录器按照收到的顺序为每条消息分配一个序列号就足够了。

于 2008-10-01T14:24:59.453 回答
2

这是一个关于 Python 计时精度的主题:

Python - time.clock() vs. time.time() - accuracy?

于 2008-10-01T13:44:13.593 回答
2

自从这个问题被提出和回答以来的几年前,这个问题已经得到了解决,至少对于 Windows 上的 CPython。在 Win7 64bit 和 Windows Server 2008 R2 上使用下面的脚本,我得到了相同的结果:

  • datetime.now()提供 1ms 的分辨率和小于 1ms 的抖动
  • 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))

结果可视化: 在此处输入图像描述

于 2014-03-05T09:46:44.900 回答
0

我要感谢 J. Cage 的最后一篇文章。

对于我的工作,跨流程和平台的事件“合理”时间安排是必不可少的。显然有很多地方会出现偏差(时钟漂移、上下文切换等),但是我认为这种准确的计时解决方案将有助于确保记录的时间戳足够准确以查看其他错误来源.

也就是说,当 MicroSeconds Matter中解释了一些我想知道的细节。例如,我认为 time.clock() 最终会换行。我认为要让它在一个长期运行的过程中工作,你可能必须处理它。

于 2008-11-12T15:51:52.890 回答
0

如果您想要 Python 中的微秒分辨率(不准确)时间戳,在Windows 中,您可以使用 Windows 的 QPC 计时器,如我在此处的回答所示:如何在 Python 中获取毫秒和微秒分辨率的时间戳。我还不确定如何在 Linux 中执行此操作,所以如果有人知道,请在上面的链接中发表评论或回答。

于 2016-08-09T01:59:53.100 回答