2008-10-01 75 views
12

最近我一直在構建一個錯誤日誌記錄應用程序,並且正在準確地對傳入數據進行時間戳記。當我準確地表達時,我的意思是每個時間戳應該相對於彼此準確(不需要同步到原子鐘或類似的東西)。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〜32ms更新一次。當我們分析數據時,問題出現了,因爲按照時間戳以外的方式排序,然後再按時間戳排序可能會使數據按錯誤順序排序(按時間順序排列)。如果時間標記精確到對時間標記發生器的任何調用都給出唯一時間標記,那將是很好的做法。

我一直在考慮一些涉及到使用time.clock()調用添加到開始日期時間的方法,但希望能夠在同一臺機器上的線程間準確工作的解決方案。任何建議將非常感激地收到。

+0

我剛剛在* Windows *中發佈了一個新答案,使用Python,您可以使用Windows QPC時鐘獲得亞微秒級* *分辨率*(不準確性)時間戳,正如我在代碼中鏈接的代碼回答。 – 2016-08-09 02:01:58

+0

爲什麼你要建立自己的日誌框架?已經有很多了,時間戳是一個解決的問題(降低到一定的準確度)。萬一你有一個沒有現有日誌框架解決的用例,你能選擇最接近的用戶並提出問題並提交你的代碼嗎? – smci 2017-07-10 15:17:52

+0

因爲〜8.5年前(當我發佈這個時),選項有些更有限。我沒有構建錯誤日誌框架,我正在寫一些東西來接收UDP數據並從中記錄信息。如果有一個可用的庫(並且我找到了)可以做到這一點,我已經完全開放使用它;-) – 2017-07-13 15:43:44

回答

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 

多進程(而不是線程),它變得有點棘手,但。

+1

我意識到這有點挑剔,但你的意思是「嚴格增加整數」而不是「單調增加整數」。單調增加的集合意味着它不會減少,但仍可能具有相同的值。 – 2008-11-12 16:12:32

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()之後測量wallclock,所以您必須請記得先「初始化」它。

+0

的確,這是它在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 2008-10-01 15:13:03

+0

我可以確認時鐘確實在我嘗試過的所有Windows機器上都更加準確。 – 2008-10-01 19:21:36

2

這是一個關於Python定時精度螺紋:

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

+0

是的,我已經看到了一個,但那些是相對於一個開始的過程或對時鐘的調用而不是絕對(ish)時間。 – 2008-10-01 15:04:10

3

「時間戳應該是相對精確的」

爲什麼時間?爲什麼不是序列號?如果它是客戶端 - 服務器應用程序的任何客戶端,則網絡延遲會使時間戳具有隨機性。

你是否匹配一些外部信息來源?說另一個應用程序的日誌?同樣,如果有網絡,那些時間不會太近。

如果您必須在不同的應用程序之間進行匹配,請考慮傳遞GUID以便兩個應用程序都記錄GUID值。那麼你可以絕對確定他們匹配,不管時間差異。

如果您希望相對的順序完全正確,那麼您的記錄器可能會按照收到的順序爲每封郵件分配一個序列號就足夠了。

5

謝謝大家的貢獻 - 他們都非常有用。 Brian的回答看起來與我最終的結果最接近(即處理它,但使用一種唯一的標識符 - 見下文),所以我已經接受了他的答案。我設法將所有各種數據接收器整合到一個單一線程中,現在使用我的新的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) 
0

我想感謝J.Cage的最後一篇文章。

對於我的工作,跨過程和平臺的「合理」事件時間安排至關重要。顯然有很多地方可能發生歪斜事件(時鐘漂移,上下文切換等),但我認爲,這種精確的時序解決方案有助於確保記錄的時間戳足夠準確,以查看其他誤差來源。

這就是說,有幾個細節我想知道在When MicroSeconds Matter解釋。例如,我認爲time.clock()將最終包裝。我認爲這是爲了長時間運行的過程,你可能需要處理它。

1

這個問題已經提出並回答了幾年,至少對於Windows上的CPython已經處理了這個問題。使用下面兩個Win7的64位和Windows Server 2008 R2中的腳本,我得到了相同的結果:

  • datetime.now()給出了1毫秒的分辨率和抖動小於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)) 

結果可視化: enter image description here

0

如果你想microsecond-分辨率(不準確)在Python時間戳,在Windows中,您可以使用Windows的QPC計時器一樣,在我的答案在這裏證明:How to get millisecond and microsecond-resolution timestamps in Python。我不知道如何在Linux中做到這一點,所以如果有人知道,請在上面的鏈接中評論或回答。