Pythonのtime.sleep()はどれほど正確ですか?


95

私はそれに浮動小数点数を与えることができます

time.sleep(0.5)

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

time.sleep(0.05)

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

回答:


78

time.sleep関数の精度は、基盤となるOSのスリープ精度に依存します。標準のWindowsのような非リアルタイムOSの場合、スリープできる最小間隔は約10〜13ミリ秒です。最小の10〜13ミリ秒を超えると、その時間から数ミリ秒以内に正確な睡眠が見られます。

更新:下記のドキュメントで言及されているように、ループでスリープを行うのが一般的です。これにより、早く目覚めたら必ずスリープに戻ります。

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

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


8
実際、Linuxカーネルはかなり長い間デフォルトでより高いティックレートに設定されているため、「最小」スリープは10msよりも1msにかなり近くなっています。保証はありません。他のシステムアクティビティにより、CPUの競合がなくても、カーネルは必要なときにすぐにプロセスをスケジュールできなくなります。それが、リアルタイムカーネルが修正しようとしていることだと思います。ただし、リアルタイムの動作が本当に必要な場合を除き、高いティックレート(カーネルHZ設定)を使用するだけで、特別なものを使用せずに、Linuxで保証されていませんが高解像度のスリープが得られます。
グレンメイナード

1
はい、そうです。私はLinux 2.6.24-24を試しましたが、1000 Hzにかなり近い更新レートを得ることができました。私がこれを行っていたときは、MacとWindowsでもコードを実行していたため、おそらく混乱していました。私はWindows XPが少なくとも約10msのティックレートを持っていることを知っています。
ジョセフリゼ

Windows 8では2ms未満になります
markmnl

2
また、精度はOSに依存するだけでなくsleep()、ドキュメントからより重要なことをしているときにWindowsとLinuxの両方でOSが何をしているかによって異なります。「一時停止時間は、システムの他の活動」。
markmnl 2014年

55

オペレーティングシステムとカーネルの違いについては非常に正しいですが、Ubuntuには細分性がなく、MS7には1 msの細分性があります。異なるティックレートだけでなく、time.sleepの異なる実装を提案します。ちなみに、詳細な検査では、Ubuntuの粒度が1μsであることが示唆されていますが、これは、精度の測定に使用するtime.time関数が原因です。 PythonでのLinuxおよびWindowsの典型的なtime.sleep動作


6
Linuxが常に要求よりも少し長くスリープすることを選択したのは興味深いことですが、Microsoftは反対のアプローチを選択しました。
jleahy 2013

2
@jleahy-Linuxのアプローチは私にとって意味があります:スリープは実際にはしばらくの間実行優先度のリリースであり、その後再びスケジューラの意志に自分を提出します(すぐに実行するようにスケジュールすることもしないこともあります) 。
2013

2
どのようにして結果を得ましたか?あなたはソースコードを提供できますか?グラフは、時間と睡眠を測定するために異なるタイマーを使用した場合のアーティファクトのように見えます(原則として、タイマー間のドリフトをランダム性のソースとして使用することもできます)。
jfs

1
@JF Sebastian-私が使用した関数はsocsci.ru.nl/wilberth/computer/sleepAccuracy.htmlにあります。そこにある3番目のグラフは、見た目と同じような効果を示していますが、1‰しかありません。
Wilbert、2015年

1
@JF Sebastian Windowsでtime.clock()を使用します
Wilbert

26

ドキュメントから:

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

そして、より具体的に WRT sleep()

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


1
誰かが「キャッチされたシグナルはそのシグナルのキャッチルーチンの実行後にsleep()を終了させるため」と説明できますか?それはどの信号を参照していますか?ありがとう!
ディエゴヘランツ2013年

1
シグナルは、OSが管理する通知(en.wikipedia.org/wiki/Unix_signal)のようなものです。つまり、OSがシグナルをキャッチした場合、そのシグナルを処理した後、sleep()が終了します。
ArianJM 2014年

24

Wilbertの回答に対する私のフォローアップを以下に示します。MacOS X Yosemiteについても同様です。まだあまり言及されていないためです。Mac OS X Yosemiteのスリープ動作

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

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

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


ベンチマークのソースコードをgithub / bitbucketにアップロードできますか?
jfs 2015年


スリープ自体は正確だと思いますが、Mac OS Xのスケジューリングは、スリープからのスリープ解除が遅れるほど高速にCPUを提供できるほど正確ではありません。正確なウェイクアップ時間が重要な場合、スリープは実際に要求された時間の0.75倍に設定し、ウェイクアップ後の時間をチェックし、正しい時間まで徐々に繰り返しスリープする必要があるようです。
ミッコランタライネン

16

見つけてみませんか:

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

ちなみに、どちらのLinuxマシンでも、HTPCで約0.1ミリ秒、ラップトップで2ミリ秒程度のエラーが発生します。


10
実証的テストでは、非常に狭い視野が得られます。これに影響を与えるカーネル、オペレーティングシステム、およびカーネル構成は多数あります。古いLinuxカーネルはデフォルトでティックレートが低くなり、より細かくなります。Unixの実装では、スリープ中の外部信号によっていつでもキャンセルされ、他の実装でも同様の中断が発生する可能性があります。
グレンメイナード

6
もちろん、経験的観察は転送できません。オペレーティングシステムとカーネルの他に、これに影響を与える一時的な問題がたくさんあります。ハードリアルタイムの保証が必要な場合は、ハードウェアからシステム全体の設計を考慮する必要があります。10msが最小の精度であるという記述を考慮すると、結果が適切であることがわかりました。私はWindowsの世界には慣れていませんが、ほとんどのLinuxディストリビューションはしばらくの間、ティックレスカーネルを実行しています。今やマルチコアが普及しているため、タイムアウトのすぐ近くでスケジュールされる可能性がかなり高くなっています。
Ants Aasma 2009

4

小さな修正ですが、信号によって睡眠が早く終了する可能性があると何人かが述べています。では3.6のドキュメントは言います、

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


3

sleep()について何も保証することはできませんが、少なくとも、あなたが伝えた限り、スリープ状態になるよう最善を尽くします(信号は、タイムアップする前にスリープを終了させることができます。長いです)。

確かに、標準のデスクトップオペレーティングシステムで取得できる最小値は約16ミリ秒(タイマーの粒度とコンテキストスイッチまでの時間)になりますが、提供された引数からの%偏差は、試行時に重要になる可能性があります。数十ミリ秒間スリープします。

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


3
ドキュメントは別の言い方をしています:>キャッチされたシグナルはそのシグナルのキャッチルーチンの実行に続いてsleep()を終了するため、実際の一時停止時間は要求された時間よりも短い場合があります。
グレンメイナード

公平なポイント、投稿を修正しましたが、sleeps()を長くすることは、短いものよりはるかに可能性が高いです。
ニックバスティン

1
2年半後...ドキュメントはまだあります。Windowsでは、シグナルはsleep()を終了しません。Python 3.2、WinXP SP3でテスト済み。
デイブ

はい。ただし、プリエンプトスリープが異常であることを示す信号(KILLなど)は、ドキュメントにも次のように記載されています。より典型的です。
markmnl 2014年

1
SingnalsとWindowsはばかげています。Windowsでは、Pythonのtime.sleep()は、Ctrl-CなどをキャプチャするためにConsoleEventで待機します。
シュレンク2014年

1

より正確またはより短いスリープ時間が必要な場合は、独自に作成することを検討してください。

import time

def sleep(duration, get_now=time.perf_counter):
    now = get_now()
    end = now + duration
    while now < end:
        now = get_now()


0
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()

変数を使用してスリープ()の引数を渡さないでください。スリープ()に直接計算を挿入する必要があります


そして私の端末の復帰

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────────────────────

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.