次のような浮動小数点数を与えることができます
time.sleep(0.5)
しかし、それはどれくらい正確ですか?私がそれを与えるなら
time.sleep(0.05)
それは本当に約50ミリ秒眠りますか?
time.sleep関数の精度は、基盤となるOSのスリープ精度によって異なります。標準のWindowsのような非リアルタイムOSの場合、スリープできる最小間隔は約10〜13ミリ秒です。最小10〜13ミリ秒を超えると、その時間から数ミリ秒以内に正確な睡眠が見られます。
更新:以下に引用されているドキュメントで言及されているように、ループでスリープを実行するのが一般的です。これにより、早期に目覚めた場合に必ずスリープに戻ることができます。
また、Ubuntuを実行している場合は、rtカーネルパッケージ(少なくともUbuntu 10.04 LTS)をインストールすることで、(RT_PREEMPTパッチが設定された)疑似リアルタイムカーネルを試すことができます。
編集:修正非リアルタイムLinuxカーネルの最小スリープ間隔は1msから10msにはるかに近いですが、非決定論的な方法で変化します。
オペレーティングシステムとカーネルの違いについては、人々はまったく正しいですが、Ubuntuでは細分性が見られず、MS7では1ミリ秒の細分性が見られます。ティックレートを変えるだけでなく、time.sleepの異なる実装を提案します。ちなみに、詳しく調べると、Ubuntuでは1μsの粒度が示唆されますが、これは、精度の測定に使用するtime.time関数によるものです。
ドキュメントから:
一方、
time()
およびの精度は、sleep()
同等のUnixよりも優れています。時間は浮動小数点数として表され、time()
利用可能な最も正確な時間を返し(利用可能な場合はUnixgettimeofday
を使用)、sleep()
ゼロ以外の分数の時間を受け入れます(Unixselect
が使用されます)。可能な場合は、これを実装します)。
そしてより具体的にはwrt sleep()
:
指定された秒数の間、実行を一時停止します。引数は、より正確なスリープ時間を示すための浮動小数点数である場合があります。実際の一時停止時間は、キャッチされたシグナルがそのシグナルのキャッチルーチンの次の実行を終了するため、要求された時間よりも短い場合があります。また、システム内の他のアクティビティのスケジュールが原因で、
sleep()
一時停止時間が任意の量だけ要求されるよりも長くなる場合があります。
Wilbertの答えに対する私のフォローアップは次のとおりです。MacOSXYosemiteについても、まだあまり言及されていないので同じです。
多くの場合、要求した時間の約1.25倍、場合によっては要求した時間の1〜1.25倍の時間眠っているように見えます。要求した時間の1.25倍を大幅に超えてスリープすることはほとんどありません(1000サンプルのうち約2倍)。
また(明示的には示されていませんが)1.25の関係は、約0.2ミリ秒を下回るまではかなり良好に保たれているようです。その後、少しあいまいになり始めます。さらに、実際の時間は、要求された時間が20ミリ秒を超えた後、要求した時間よりも約5ミリ秒長く落ち着くようです。
繰り返しになりますがsleep()
、OS Xでの実装は、WindowsやWilbertが使用していたLinuxカーネルとはまったく異なるようです。
見つけてみませんか:
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ミリ秒のエラーが発生します。
より高い精度またはより短い睡眠時間が必要な場合は、独自に作成することを検討してください。
import time
def sleep(duration, get_now=time.perf_counter):
now = get_now()
end = now + duration
while now < end:
now = get_now()
ちょっとした訂正ですが、何人かの人々は、信号によって睡眠を早期に終わらせることができると述べています。3.6のドキュメントでは、次のように述べています。
バージョン3.5で変更:シグナルハンドラーが例外を発生させた場合を除いて、スリープがシグナルによって中断された場合でも、関数は少なくとも数秒スリープするようになりました(理論的根拠についてはPEP 475を参照)。
sleep()については、あなたが言っている限り、少なくとも睡眠に最善を尽くすことを除いて、実際には何も保証できません(信号は、時間がなくなる前にあなたの睡眠を殺す可能性があり、さらに多くのことがそれを実行させることができます長さ)。
確かに、標準のデスクトップオペレーティングシステムで取得できる最小値は約16ミリ秒(タイマーの粒度とコンテキストスイッチまでの時間)ですが、試してみると、提供された引数からの偏差の割合が大きくなる可能性があります数十ミリ秒スリープします。
シグナル、GILを保持している他のスレッド、カーネルスケジューリングの楽しみ、プロセッサ速度のステッピングなどはすべて、スレッド/プロセスが実際にスリープしている時間で大混乱を引き起こす可能性があります。
def test():
then = time.time() # get time at the moment
x = 0
while time.time() <= then+1: # stop looping after 1 second
x += 1
time.sleep(0.001) # sleep for 1 ms
print(x)
Windows 7 / Python 3.81000
では、スリープ値をに設定しても返されます0.0005
完璧な1ms
最近、Windows10のPython3.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─────────────────────
このtime.sleep
メソッドは、Pythonの次のリリース(3.11)で大幅にリファクタリングされています。これで、WindowsプラットフォームとUnixプラットフォームの両方で同様の精度が期待でき、デフォルトでは常に最高の精度が使用されます。新しいドキュメントの関連部分は次のとおりです。
Windowsでは、secsがゼロの場合、スレッドは残りのタイムスライスを、実行の準備ができている他のスレッドに放棄します。実行する準備ができているスレッドが他にない場合、関数はすぐに戻り、スレッドは実行を続行します。Windows 8.1以降では、実装は100ナノ秒の解像度を提供する高解像度タイマーを使用します。secsがゼロの場合、Sleep(0)が使用されます。
Unixの実装:
- 可能な場合はclock_nanosleep()を使用します(解像度:1ナノ秒)。
- または、可能な場合はnanosleep()を使用します(解像度:1ナノ秒)。
- または、select()を使用します(解像度:1マイクロ秒)。
したがって、Python 3.11以降のほとんどのプラットフォームでは、呼び出すtime.sleep
だけで問題ありません。これはすばらしいニュースです。@wilbertのものと同様に、この新しい実装のクロスプラットフォームベンチマークを実行するとよいでしょう。