web-dev-qa-db-ja.com

pythonのtime.sleep()はどれくらい正確ですか?

次のような浮動小数点数を指定できます

time.sleep(0.5)

しかし、それはどれほど正確ですか?あげたら

time.sleep(0.05)

本当に約50ミリ秒スリープしますか?

80
Claudiu

Time.sleep関数の精度は、基盤となるOSのスリープ精度に依存します。ストックWindowsのような非リアルタイムOSの場合、スリープできる最小間隔は約10〜13ミリ秒です。最小10〜13ミリ秒を超えると、その時間の数ミリ秒以内に正確なスリープが発生します。

更新:以下に引用したドキュメントで言及されているように、ループをスリープ状態にするのが一般的です。これにより、早起きした場合に確実にスリープ状態に戻ります。

また、Ubuntuを実行している場合は、rtカーネルパッケージ(少なくともUbuntu 10.04 LTS)をインストールすることで、擬似リアルタイムカーネル(RT_PREEMPTパッチセットを使用)を試すことができます。

編集:修正非リアルタイムLinuxカーネルの最小スリープ間隔は1ミリ秒と10ミリ秒に非常に近いですが、非決定的な方法で変化します。

68
Joseph Lisee

オペレーティングシステムとカーネルの違いについては人々はまったく正しいのですが、Ubuntuには粒度がなく、MS7には1ミリ秒の粒度があります。異なるティックレートだけでなく、time.sleepの異なる実装を提案します。ちなみに、より詳細な検査では、Ubuntuで1μsの粒度が提案されていますが、これは精度を測定するために使用するtime.time関数によるものです。 Linux and Windows typical time.sleep behaviour in Python

51
Wilbert

ドキュメント から:

一方、time()およびsleep()の精度は、Unixの同等のものよりも優れています。時間は浮動小数点数として表され、time()は最も正確な時間を返します使用可能(使用可能な場合はgettimeofdayを使用)、sleep()はゼロ以外の小数部の時刻を受け入れます(使用可能な場合は、Unix selectを使用してこれを実装します)。

そして より具体的に w.r.t. sleep()

指定された秒数の間、実行を一時停止します。引数は、より正確なスリープ時間を示すために浮動小数点数にすることができます。実際の一時停止時間は、要求されたものより短くなる可能性がありますキャッチされたシグナルは、そのシグナルのキャッチルーチンの実行後にsleep()を終了します。また、システム内の他のアクティビティのスケジューリングのために、一時停止時間は、任意の量で要求されるよりも長くなる可能性があります

26
Stephan202

Wilbertの答えへの私のフォローアップです。MacOS X Yosemiteについても同じです。まだ言及されていないので。Sleep behavior of Mac OS X Yosemite

多くの場合、要求する時間の約1.25倍の時間でスリープし、要求する時間の1倍から1.25倍の間でスリープする場合があります。リクエストした時間の1.25倍を大幅に超えてスリープすることはほとんどありません(1000サンプルのうち2倍)。

また、(明示的には示されていませんが)1.25の関係は、約0.2ミリ秒未満になるまでかなりよく維持されるようです。その後、少しあいまいになります。また、実際の時間は、要求された時間が20ミリ秒を超えた後、要求した時間よりも約5ミリ秒長く安定するようです。

繰り返しますが、OS Xでのsleep()の実装は、WindowsやLinuxカーネルのWilbertが使用していたものとはまったく異なるようです。

18
Tim Supinie

なぜあなたは見つけませんか:

from datetime import datetime
import time

def check_sleep(amount):
    start = datetime.now()
    time.sleep(amount)
    end = datetime.now()
    delta = end-start
    return delta.seconds + delta.microseconds/1000000.

error = sum(abs(check_sleep(0.050)-0.050) for i in xrange(100))*10
print "Average error is %0.2fms" % error

記録のために、HTPCで約0.1ミリ秒、ラップトップで2ミリ秒の両方のLinuxマシンのエラーが発生します。

15
Ants Aasma

わずかな修正ですが、数人の人々は、睡眠は信号によって早期に終了できると述べています。 .6ドキュメント では、

バージョン3.5で変更:シグナルハンドラーが例外を発生させた場合を除き、関数はスリープによってシグナルが中断された場合でも少なくとも秒スリープするようになりました(根拠については PEP 475 を参照)。

4
user405

Sleep()について何も保証することはできませんが、少なくともあなたがそれを言っている限りは睡眠のために最善の努力をすることを除いて(時間切れになる前にシグナルがあなたの睡眠を殺すことができます、そして多くのものがそれを実行させることができます)長いです)。

確かに、標準のデスクトップオペレーティングシステムで取得できる最小値は約16ミリ秒(タイマーの細分性とコンテキスト切り替えまでの時間)になりますが、チャンスは、提供しようとする引数からの%偏差が重要になることです。数十ミリ秒スリープします。

シグナル、GILを保持する他のスレッド、カーネルスケジューリングの楽しさ、プロセッサの速度ステップなどはすべて、スレッド/プロセスが実際にスリープする期間で大混乱を引き起こす可能性があります。

2
Nick Bastin

これを最近、Windows 10でPython 3.7でテストしました。精度は約1ミリ秒でした。

def start(self):
    sec_arg = 10.0
    cptr = 0
    time_start = time.time()
    time_init = time.time()
    while True:
        cptr += 1
        time_start = time.time()
        time.sleep(((time_init + (sec_arg * cptr)) - time_start ))

        # AND YOUR CODE .......
        t00 = threading.Thread(name='thread_request', target=self.send_request, args=([]))
        t00.start()

Sleep()の引数を渡すために変数を使用しないでください。sleep()に計算を直接挿入する必要があります


そして、私の端末の戻り

1─────17:20:16.891────────────────────

2─────17:20:18.891────────────────────

3─────17:20:20.891────────────────────

4─────17:20:22.891────────────────────

5─────17:20:24.891────────────────────

....

689───17:43:12.891─────────────────────

690───17:43:14.890─────────────────────

691───17:43:16.891─────────────────────

692───17:43:18.890─────────────────────

693───17:43:20.891─────────────────────

...

727───17:44:28.891─────────────────────

728───17:44:30.891─────────────────────

729───17:44:32.891─────────────────────

730───17:44:34.890─────────────────────

731───17:44:36.891─────────────────────

0
forrest