Genaues timestamping in Python-Protokollierung
Frage
Ich habe den Aufbau eine Fehlerprotokollierung App vor kurzem und war nach einer Art und Weise von genau die eingehenden Daten Timestamping. Wenn ich sage, genau meine ich jeden Zeitstempel zueinander (keine Notwendigkeit, so zu einer Atomuhr oder irgendetwas zu synchronisieren) genaue relative sein sollte.
Ich habe mit datetime.now () als ersten Stich, aber das ist nicht perfekt:
>>> 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.
Die Änderungen zwischen den Takten der ersten Sekunde der Proben wie folgt aussehen:
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
So sieht es aus wie die Timer-Daten nur alle ~ 15-32ms auf meiner Maschine aktualisiert werden. Das Problem kommt, wenn wir die Daten zu analysieren kommen, weil das Sortieren durch etwas anderes als der Zeitstempel und dann durch Zeitstempel Sortierung wieder können die Daten in der falschen Reihenfolge (chronologisch) verlassen. Es wäre schön, die Zeitstempel genau auf den Punkt zu haben, dass jeder Aufruf den Zeitstempel-Generator einen eindeutigen Zeitstempel gibt.
Ich hatte einige Verfahren vorgeschlagen worden, unter Berücksichtigung eines time.clock Beteiligung mit () Aufruf zu einer Startdatetime hinzugefügt, würde aber eine Lösung zu schätzen wissen, die genau über Threads auf derselben Maschine funktionieren würden. Irgendwelche Vorschläge wäre sehr dankbar empfangen.
Lösung
Sie sind unwahrscheinlich ausreichend feinkörnige Kontrolle zu bekommen, dass Sie die Möglichkeit, vollständig beseitigen von doppelten Zeitstempeln - müssen Sie Auflösung kleiner ist als die Zeit, um ein Datetime-Objekt zu erzeugen, es dauert. Es gibt ein paar andere Ansätze, die Sie ergreifen könnten damit umgehen:
-
Abkommen mit ihm. Hinterlassen Sie Ihre Zeitstempel nicht eindeutig, wie sie sind, sondern verlassen sich auf Pythons Art stabil mit Neuordnungs Problemen zu befassen. Sortierung auf Zeitstempel zuerst , dann behält etwas anderes den Zeitstempel Ordnung - man muss nur vorsichtig sein, immer dann starten aus der Zeitstempel geordnete Liste jedes Mal, anstatt mehrere Sorten auf der gleichen Liste zu tun.
-
Fügen Sie Ihren eigenen Wert Eindeutigkeit zu erzwingen. Z.B. ein Inkrementieren Ganzzahl als Teil des Schlüssels umfassen, oder anhängen solchen Wert nur dann, wenn die Zeitstempel verschieden sind. ZB.
Im Folgenden werden eindeutige Zeitmarke Werte garantieren:
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
Für mehrere Prozesse (statt Threads), wird es allerdings etwas schwieriger.
Andere Tipps
time.clock () nur misst Wanduhr Zeit unter Windows. Auf anderen Systemen time.clock () tatsächlich misst CPU-Zeit. Auf diesen Systemen time.time () ist besser geeignet für die Wanduhr Zeit, und es hat eine so hohe Auflösung wie Python verwalten können - was so hoch wie das OS ist verwalten; in der Regel unter Verwendung von gettimeofday (3) (Mikrosekunde Auflösung) oder ftime (3) (Millisekundenauflösung.) Andere OS Einschränkungen tatsächlich die reale Auflösung viel höher als machen. datetime.datetime.now () verwendet time.time (), so time.time () nicht direkt besser sein.
Für das Protokoll, wenn ich datetime.datetime.now () in einer Schleife verwenden, sehe ich über eine 1/10000 Sekunde Auflösung. Vom Blick auf Ihre Daten haben Sie viel, viel gröberen Auflösung als das. Ich bin mir nicht sicher, ob es etwas gibt, Python als solche können tun, obwohl Sie in der Lage sein können, das Betriebssystem zu überzeugen, besser mit anderen Mitteln zu tun.
Ich scheine, dass unter Windows zu erinnern, time.clock () ist eigentlich (leicht) genauer als time.time (), aber es misst Wanduhr seit dem ersten Aufruf (), um time.clock, so dass Sie dürfen nicht vergessen, zu 'initialisieren' es zuerst.
Vielen Dank für Ihre Beiträge - sie alle sehr nützlich sein haben. Brians Antwort scheint am nächsten, was ich ging schließlich mit (das heißt mit ihr umgehen, sondern eine Art eindeutiger Kennung verwenden - siehe unten), so hat mich seine Antwort akzeptiert. Ich schaffte es, alle verschiedenen Datenempfänger in einem einzigen Thread zu konsolidieren, die ist, wo die timestamping jetzt meine neue AccurrateTimeStamp Klasse erfolgt über. Was ich so lange, wie der Zeitstempel ist die erste Sache, um die Uhr zu nutzen.
getan funktioniertAls S.Lott schreibt vor, ohne Echtzeit-Betriebssystem, sie gehen nie absolut perfekt sein. Ich wollte eigentlich nur etwas, das mich auf jeden eingehenden Datenblock sehen relativ lassen würde, wenn die Dinge so, was ich unten bekam empfangen werden wird gut funktionieren.
Danke nochmal alle!
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)
„Zeitstempel sollte genau relativ zueinander sein“
Warum Zeit? Warum nicht eine Sequenznummer? Wenn es ein Client von Client-Server-Anwendung ist, die Netzwerk-Latenz macht Zeitstempel Art von zufällig.
passen Sie einige externe Informationsquelle? Sagen Sie ein Protokoll auf einer anderen Anwendung? Auch wenn es ein Netzwerk ist, werden nicht diese Zeiten zu nahe.
Wenn Sie die Dinge zwischen den einzelnen Apps übereinstimmen müssen, sollten Sie GUID um vorbei, so dass beide Anwendungen den GUID-Wert log. Dann könnten Sie absolut sicher sein, sie übereinstimmen, unabhängig von den Unterschieden Timing.
Wenn Sie die relativ wollen , um genau das Richtige zu sein, vielleicht ist es genug für den Logger eine Sequenznummer zu jeder Nachricht in der Reihenfolge zugewiesen wurden sie empfangen werden.
Hier ist ein Thread zu Python Timing-Genauigkeit:
Python - time.clock () vs. time.time () - Genauigkeit / p>
Ein paar Jahre vergangen, seit der Frage gestellt wurde und beantwortet, und dies mit zumindest für CPython unter Windows behandelt wurde. Mit dem Skript unten auf beiden Win7 64bit und Windows Server 2008 R2, habe ich die gleichen Ergebnisse:
-
datetime.now()
liefert eine Auflösung von 1 ms und einem Jitter kleiner als 1 ms -
time.clock()
liefert eine Auflösung von besser als 1 us und einen Jitter viel kleiner als 1 ms
Das Skript:
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))
Die Ergebnisse sichtbar gemacht:
Ich wollte J. Cage für diesen letzten Beitrag danken.
Für meine Arbeit, „vernünftige“ Timing von Ereignissen über Prozesse und Plattformen unerlässlich. Natürlich gibt es viele Orte, wo die Dinge schief gehen können (Taktdrift, Kontextwechsel, etc.), aber diese genaue Timing-Lösung wird, glaube ich, dazu beitragen, dass die Zeit aufgezeichnet Stempel sind ausreichend genau die anderen Fehlerquellen zu sehen .
Das heißt, es gibt ein paar Details, die ich über Wunder, dass in Wenn Mikrosekunden Materie . Zum Beispiel denke ich time.clock () wird schließlich wickeln. Ich denke, dies für einen langen laufenden Prozess arbeiten, könnten Sie das handhaben müssen.
Wenn Sie microsecond- Auflösung (NOT Genauigkeit) Zeitstempel in Python, in Windows Sie Windows der QPC Timer verwenden können, wie hier in meiner Antwort demonstriert: Wie bekommt Millisekunden und Mikrosekunde-Auflösung Zeitstempel in Python . Ich bin mir nicht sicher, wie dies noch in Linux zu tun, also wenn jemand weiß, bitte kommentieren oder in dem obigen Link zu beantworten.