質問

エラーログアプリを最近作成しましたが、受信データに正確にタイムスタンプを付ける方法を探していました。正確に言うと、各タイムスタンプは互いに正確でなければなりません(原子時計などに同期する必要はありません)。

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-32msごとにのみ更新されるようです。タイムスタンプ以外のもので並べ替えてから再びタイムスタンプで並べ替えると、データが間違った順序で(時系列に)残るため、データを分析するときに問題が発生します。タイムスタンプジェネレーターを呼び出すと一意のタイムスタンプが返されるように、タイムスタンプを正確にするとよいでしょう。

開始日時に追加されたtime.clock()呼び出しを使用する方法を検討していましたが、同じマシンのスレッド間で正確に動作するソリューションを評価したいと思います。どんな提案も非常に感謝されます。

役に立ちましたか?

解決

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

  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

(スレッドではなく)複数のプロセスの場合、少し複雑になります。

他のヒント

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()を最初に呼び出してからwallclockを測定することを思い出すようです。最初に「初期化」します。

あなたの貢献に感謝します-それらはすべて非常に有用です。ブライアンの答えは、最終的に私が行ったものに最も近いようです(つまり、それに対処しますが、一意の識別子の種類を使用します-以下を参照)ので、私は彼の答えを受け入れました。新しい 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)

"タイムスタンプは相互に正確である必要があります"

なぜですか?なぜシーケンス番号ではないのですか?クライアントサーバーアプリケーションのクライアントである場合、ネットワーク遅延によりタイムスタンプがランダムになります。

外部の情報源と一致していますか?別のアプリケーションでログを作成しますか?繰り返しますが、ネットワークがあれば、それらの時間は近づきすぎません。

別々のアプリ間で物事を一致させる必要がある場合は、両方のアプリがGUID値を記録するようにGUIDを渡すことを検討してください。そうすれば、タイミングの違いに関係なく、それらが確実に一致することを確実にすることができます。

相対の順序を正確にしたい場合は、ロガーが受信した順序で各メッセージにシーケンス番号を割り当てるだけで十分かもしれません。

Pythonのタイミング精度に関するスレッドです:

Python-time.clock()vs. time.time()-精度?

少なくともWindows上のCPythonについては、質問が尋ねられてから数年が経ち、これは対処されました。 Win7 64ビットと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))

視覚化された結果: ここに画像の説明を入力してください

この最後の投稿についてJ. Cageに感謝したかった。

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

とはいえ、マイクロ秒が重要な場合。たとえば、time.clock()は最終的にラップすると思います。これが長時間実行されるプロセスで機能するには、それを処理する必要があるかもしれません。

Pythonでマイクロ秒-解像度(精度ではない)タイムスタンプが必要な場合、 Windows では、私の回答で示されているように、WindowsのQPCタイマーを使用できます: Pythonでミリ秒とマイクロ秒の解像度のタイムスタンプを取得する方法。 Linuxでこれを行う方法はまだわかりません。だれかが知っている場合は、上のリンクでコメントまたは回答してください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top