🍲

Python の time.sleep の上限

に公開

これは何?

Python で、雑に「一生寝てろ」という気持ちで

Python3
time.sleep(1<<62)

としたら OverflowError: timestamp too large to convert to C PyTime_t と言われ、え、上限あるの? となったのでそのことを調べた話。

ちなみに、(1<<62) と書いたのは、整数になっても無理なくという気持ち。

調査対象

手元の環境で uv が入れてくれる範囲内で試した。
具体的には

名前 下限 上限
CPython 3.8 3.14
Pypy 3.8 (PyPy 7.3.11) 3.11 (PyPy 7.3.20)
Graal 3.10 (Java 22) 3.12 (Java 25)

という感じ。ハードウェアは Apple Silicon の MacBook。

二分探索

結果は下表

バージョン 上限
CPython-3.14 9223372036.854774 = 0x1.12e0be826d694p+33
CPython-3.13 9223372036.854774 = 0x1.12e0be826d694p+33
CPython-3.12 9223372036.854774 = 0x1.12e0be826d694p+33
CPython-3.11 9223372036.854774 = 0x1.12e0be826d694p+33
CPython-3.10 100000000.99999899 = 0x1.7d78403ffffbcp+26
CPython-3.9 100000000.99999899 = 0x1.7d78403ffffbcp+26
CPython-3.8 100000000.99999899 = 0x1.7d78403ffffbcp+26
pypy-3.11 9223372036.854774 = 0x1.12e0be826d694p+33
pypy-3.10 100000000.99999999 = 0x1.7d78403ffffffp+26
pypy-3.9 100000000.99999999 = 0x1.7d78403ffffffp+26
pypy-3.8 100000000.99999999 = 0x1.7d78403ffffffp+26
graalpy-3.12 9223372036854776.0 = 0x1.0624dd2f1a9fcp+53
graalpy-3.11 9223372036854776.0 = 0x1.0624dd2f1a9fcp+53

見どころ

CPython

3.10 までと 3.11 からで仕様が変わったのかな。

3.10 までは 約 1億秒。3年ちょい。
上限が「1億秒 + 1秒 の手前」なのはどうかと思う。

3.11 からの 約 92億秒 は、10進数でも2進数でも中途半端な値となっていてパット見よくわからないけど、どうも 2の63乗 nano秒 ということらしい。

PyPy

表を見ると CPython とおなじに見えるが、実はちょっと違う。

雑な動作

longsleep.py
import time

t0=time.time()
time.sleep(2**60+1)
print(f"ok: dur={time.time()-t0:.2f}s")

を実行すると、CPython では

  File "/略/longsleep.py", line 4, in <module>
    time.sleep(2**60+1)
    ~~~~~~~~~~^^^^^^^^^
OverflowError: timestamp too large to convert to C PyTime_t

と、ちゃんと例外になるが、pypy 3.8〜3.11 では

ok: dur=1.01s

などとなる。エラー処理が不足している。

GraalPy

Graal の Python で現れる 約 9223兆秒 という値は、2**63/1000 に等しい。ミリ秒単位で 64bit 符号付き整数を入れてるんだと思う。

所感

このような処理で、CPython・PyPy・graalpy に差異があるのは意外だった。

Windows では試していないけど、なんか違う結果になるかもしれないね。

CPython 3.10 などの 上限「約 (1億+1)秒」はもっと意外だった。ちょっとみっともない印象。

いずれにせよ、ちゃんとしていれば 3年 sleep とかしたいことはないので困ることはないのだけれど。

あ、PyPy でエラー処理が不足しているのは稀に困るかもね。

Discussion