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.

サンプルの最初の 1 秒間のクロック間の変化は次のようになります。

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() 呼び出しを使用するいくつかの方法を検討していましたが、同じマシン上の複数のスレッドで正確に機能するソリューションがあれば幸いです。どんな提案でも非常に感謝しています。

4

8 に答える 8

12

time.clock() は、Windows のウォールクロック時間のみを測定します。他のシステムでは、time.clock() は実際に CPU 時間を測定します。これらのシステムでは、 time.time() はウォールクロック時間により適していて、Python が管理できるほど高い解像度を持っています。これは OS が管理できるほど高いです。通常は gettimeofday(3) (マイクロ秒の解像度) または ftime(3) (ミリ秒の解像度) を使用します。その他の OS 制限により、実際の解像度は実際にはそれよりもはるかに高くなります。datetime.datetime.now() は time.time() を使用するため、time.time() を直接使用しても改善されません。

記録のために、ループで datetime.datetime.now() を使用すると、約 1/10000 秒の解像度が表示されます。データを見ると、それよりもはるかに粗い解像度があります。他の手段でOSをより良くするよう説得できるかもしれませんが、Python自体にできることがあるかどうかはわかりません。

Windowsでは、time.clock()は実際にはtime.time()よりも(わずかに)正確ですが、time.clock()への最初の呼び出し以降のウォールクロックを測定するため、「初期化することを覚えておく必要があります。それを最初に。

于 2008-10-01T12:54:25.957 に答える
7

タイムスタンプが重複する可能性を完全に排除できるほどきめ細かい制御が得られる可能性は低いです。datetime オブジェクトの生成にかかる時間よりも小さい解像度が必要です。それに対処するために取ることができる他のいくつかのアプローチがあります:

  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

皆さんの貢献に感謝します - それらはすべて非常に役に立ちました。ブライアンの答えは、私が最終的に行ったものに最も近いように思われるので (つまり、それに対処しますが、一種の一意の識別子を使用します。以下を参照してください)、彼の答えを受け入れました。さまざまなデータ レシーバーをすべて 1 つのスレッドに統合することができました。このスレッドでは、新しいAccurrateTimeStampクラスを使用してタイムスタンプが実行されます。私が行ったことは、タイムスタンプが時計を使用する最初のものである限り機能します。

S.Lott が規定しているように、リアルタイム OS がなければ、完全に完璧になることはありません。私が実際に望んでいたのは、データが受信されたときに、着信するデータの各チャンクに関連して表示できるものだけだったので、以下に示したものがうまく機能します。

みんなありがとう!

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 に答える
0

Python でマイクロ秒単位の解像度(精度ではない) のタイムスタンプが必要な場合は、 Windows でWindows の QPC タイマーを使用できます。Linuxでこれを行う方法はまだわからないので、知っている人は上のリンクにコメントするか回答してください。

于 2016-08-09T01:59:53.100 に答える
0

この最後の投稿について、J. Cage に感謝したいと思います。

私の仕事では、プロセスとプラットフォーム全体でイベントの「合理的な」タイミングが不可欠です。物事がずれてしまう可能性のある場所は明らかにたくさんありますが (クロックのドリフト、コンテキストの切り替えなど)、この正確なタイミング ソリューションは、記録されたタイム スタンプが他のエラーの原因を確認するのに十分正確であることを保証するのに役立つと思います。 .

そうは言っても、 When MicroSeconds Matterで説明されているいくつかの詳細について疑問に思っています。たとえば、 time.clock() は最終的にラップすると思います。これが長時間実行されるプロセスで機能するためには、それを処理する必要があるかもしれません。

于 2008-11-12T15:51:52.890 に答える