Python WebAcademy Blog

Pythonのtimeモジュールとは?sleepで待つ・処理時間を測る基本を初心者向けに解説

|

Pythonのtimeモジュールを、IT初心者向けにやさしく解説します。time.sleep()で処理を待たせる書き方と、指定した秒数ぴったりでは戻らない理由、Webアクセスの間隔調整や失敗時の指数バックオフ、time.time()ではなくperf_counter()で処理時間を測るべき理由、monotonicやprocess_timeとの使い分け、timeitで正しく速さを比べる方法まで、手元で動かせるコードと表を並べながら順番に整理します。

書いたプログラムが一瞬で走りきってしまい、相手のサーバーへ連続でアクセスしてしまった。あるいは、動きが遅いのは分かるのに、どこが遅いのかまでは分からない。

そんな場面に出会ったことはありませんか。

どちらも、時間を扱うほんの少しの知識で解決します。使うのは、Pythonに最初から入っているtimeモジュールです。

インストールは要りません。import time と書くだけで、待つことも測ることもできるようになります。

この記事では、timeモジュールの中でも出番の多い機能を、実際のコードと一緒に順番に整理していきます。

timeモジュールは、時間そのものを扱う道具箱

まずは立ち位置から確認しましょう。timeはPythonに標準で付いてくるライブラリで、追加の準備なしにすぐ使えます。

できることは大きく2つです。処理を待たせることと、時間の長さを測ること。

どちらもOSが持っている機能を薄く包んだつくりになっています。だから動作が軽く、どの環境でもだいたい同じようにふるまいます。

datetimeとtimeは、目的がまったく違う

ここは初心者がよく混乱するところです。日付を扱うdatetimeというモジュールも別にあるので、どちらを使えばいいのか迷ってしまいます。

区別はかんたんです。人間に見せる日付や日時ならdatetime、機械として時間を数えるならtime、と考えてください。

具体的な場面で並べると、境目がはっきりします。

やりたいこと 使うもの
3日後の日付を求める datetime
2026年8月25日という形で表示する datetime
処理を5秒だけ止める time
処理にかかった秒数を測る time

日付の計算やタイムゾーンの扱いを詳しく知りたい方は、こちらでまとめています。【関連記事】Pythonのdatetimeを完全攻略!日付の計算やタイムゾーンで迷わないために

time.sleep()で、処理をいったん止める

timeモジュールでいちばん出番が多いのがこれです。指定した秒数だけ、プログラムの進行を止められます。

さっそく手元で動かしてみましょう。

import time

print("開始")
time.sleep(3)      # 3秒止まる
print("3秒たちました")

time.sleep(0.5)    # 小数も渡せる
print("さらに0.5秒たちました")

渡す秒数は小数でも構いません。0.5と書けば0.5秒、0.1と書けば0.1秒だけ待ちます。

止まるのは、その処理を動かしているスレッドだけです。むずかしく感じるかもしれませんが、ふつうのスクリプトならプログラム全体が止まると考えて差し支えありません。

指定した秒数ぴったりでは戻ってこない

知っておくと得をする性質があります。time.sleep(1) と書いても、きっかり1秒後に再開するとは限らないのです。

公式ドキュメントにも、システム内のほかの処理の都合で、要求した時間より長くなることがあると書かれています。sleepが約束してくれるのは最低の待ち時間であって、上限ではありません。

精度そのものは年々よくなっています。Python 3.11では、Windowsで分解能の高いタイマーが使われるようになり、Unixでもclock_nanosleep()nanosleep()が使えるときはそちらを使うよう変わりました。

とはいえ、ミリ秒単位の正確さが求められる用途にsleepを持ち出すのは避けたほうが無難です。数秒の待機や、次に紹介するアクセス間隔の調整になら、精度は十分すぎるほどあります。

待ち時間が必要になる、現実の場面

わざわざ待つ処理なんて要るのか、と思うかもしれません。ところが実務では、驚くほどよく使います。

いちばん多いのは、Webからデータを取ってくる場面です。連続してアクセスすると相手のサーバーに負荷をかけるので、1件ごとに少しだけ間を空けます。

import time
import requests

urls = ["https://example.com/1", "https://example.com/2"]

for url in urls:
    response = requests.get(url, timeout=10)
    print(url, response.status_code)
    time.sleep(1)      # 次のアクセスまで1秒空ける

この1行は、相手のサーバーを守るためのマナーでもあります。 自分のプログラムが原因で相手に迷惑をかけると、アクセスそのものを断られてしまうことさえあります。

HTTP通信の基本から確認しておきたい方は、こちらもあわせてどうぞ。【関連記事】Pythonのrequestsとは?WebからデータをとってくるHTTP通信の基本を初心者向けに解説

失敗したときは、待つ時間を伸ばしていく

通信が失敗したときの再挑戦にも、sleepが登場します。ただし、毎回同じ秒数で待つのはあまり良い手ではありません。

相手が混み合っているときに一定の間隔で叩き続けると、その混雑をさらに悪化させてしまうからです。失敗するたびに待ち時間を倍にしていくほうが、相手にも自分にも優しいやり方になります。

import time

for attempt in range(5):
    try:
        result = call_api()      # 通信する処理(例)
        break
    except TimeoutError:
        wait = 2 ** attempt      # 1秒、2秒、4秒、8秒…と伸びていく
        print(f"{wait}秒待ってから再挑戦します")
        time.sleep(wait)

この待ち方は指数バックオフと呼ばれます。私は10年ほどエンジニアとして開発に関わってきましたが、固定間隔のリトライが障害の復旧をかえって長引かせた現場を何度も見てきました。

処理時間を測るなら、perf_counter()を使う

ここからは測るほうの話です。遅い処理を速くしたいとき、まず必要になるのは、どこにどれだけ時間がかかっているかという数字です。

検索するとtime.time()で測る例が多く出てきます。ですが、経過時間の測定に向いているのは別の関数です。

import time

start = time.perf_counter()

total = sum(range(10_000_000))

elapsed = time.perf_counter() - start
print(f"かかった時間: {elapsed:.3f}秒")

time.perf_counter() は、短い時間を測るために用意された、いちばん分解能の高い時計です。返ってくる値そのものに意味はなく、2回呼んだときの差だけを使います。

では、なぜtime.time()ではないのでしょうか。理由は、time.time()が指しているのが現在時刻だからです。

現在時刻は、ほかのコンピュータと時計を合わせるなどの理由で、途中で修正されることがあります。運悪くその瞬間をまたいでしまうと、測定結果がずれたり、ときにはマイナスになったりします。

時刻を記録したいときはtime.time()、時間の長さを測りたいときはtime.perf_counter() この一言を覚えておけば、もう迷いません。

4つの時計を、目的で選び分ける

timeモジュールには時計がいくつもあり、名前を眺めただけでは違いが分かりません。ここで整理しておきましょう。

関数 何を返すか 向いている用途 sleep中の時間
time.time() エポックからの経過秒数 時刻の記録、ファイル名 含む
time.monotonic() 巻き戻らない時刻 タイムアウト、間隔の判定 含む
time.perf_counter() 最も分解能の高い時刻 処理時間の計測 含む
time.process_time() CPUが働いた時間 計算の重さの調査 含まない

エポックというのは時間を数える基準点のことで、WindowsやUnix系の多くの環境では1970年1月1日0時(UTC)を指します。time.time()は、そこからの経過秒数を小数で返しているわけです。

time.monotonic()は、名前のとおり巻き戻らないことが保証された時計です。時刻合わせの影響を受けないので、タイムアウトの判定のように、途中で時間が逆戻りしたら困る場面で使われます。

最後のprocess_time()だけ、右端の列が違うことに気づいたでしょうか。これはCPUが実際に働いた時間なので、通信の待ち時間やsleepの時間は数えません。

つまり、全体では10秒かかったのにprocess_time()では0.2秒しか進んでいなければ、その処理は計算ではなく待ちで時間を使っていると分かります。原因の切り分けに、とても役立つ性質です。

小数の誤差が気になる場合は、末尾に_nsが付いたtime.perf_counter_ns()のような関数も使えます。こちらは整数のナノ秒で結果を返してくれます。

小さなコードの速さを比べるなら、timeit

自分で測る方法を覚えたところで、注意点をひとつ。1回だけ測った数字は、ほとんど参考になりません。

パソコンは同時にいろいろな処理を抱えているので、まったく同じコードでも測るたびに結果が揺れます。一瞬で終わる処理ほど、その揺れの影響を大きく受けてしまいます。

そこで使うのが、標準ライブラリのtimeitです。同じコードを何度も繰り返し実行して、ばらつきをならしてくれます。

python -m timeit -n 1000 "'-'.join(str(n) for n in range(100))"

コマンドラインからそのまま呼べるのが便利なところです。-nは1セットあたりの繰り返し回数、-rは測定を何セット行うかの指定になります。

もちろんPythonのコードの中からも使えます。ただしtimeit.timeit()は回数を指定しないと100万回も実行するので、重い処理を測るときはnumberを必ず小さくしてください。

そもそも速さは、書き方そのものによって桁が変わることもあります。処理の重さを見積もる考え方は、こちらで解説しています。【関連記事】「実行時間が終わらない…」を卒業する!あなたのコードを100倍速くする計算量の考え方

現在時刻を、人が読める形にする

timeモジュールにも、時刻を文字列へ整える機能があります。ログのファイル名を作るときなどに手軽です。

数値のままでは読めないので、いったん地方時に直してから書式を当てます。

import time

now = time.time()
print(now)                       # 1787000000.123456 のような数値

local = time.localtime(now)
print(time.strftime("%Y-%m-%d %H:%M:%S", local))
print(time.strftime("log_%Y%m%d.txt", local))

localtime()でその環境の地方時に直し、strftime()で好きな書式へ整えます。%Yが4桁の年、%mが月、%dが日です。

ただし、日付の計算や表示が目的の中心になるなら、素直にdatetimeを使うほうが読みやすくなります。timeのこの機能は、ちょっとした記録に添えるくらいがちょうどよい距離感です。

初心者がつまずきやすいところ

最後に、実際によく見かける失敗をまとめておきます。当てはまるものがないか、確認してみてください。

症状 原因 対処
sleepでNameErrorが出る import time を書いていない ファイルの先頭で読み込む
sleepが急に使えなくなる timeという名前の変数を作った 変数名を別のものに変える
測った時間がマイナスになる time.time()で測っている perf_counter()に変える
待っている間に画面が固まる GUIアプリの本体でsleepした フレームワークのタイマー機能を使う
何度測っても同じ数字が出る 表示を丸めすぎている :.3fのように桁数を増やす

とくに多いのが2つめです。time = 0のような行を書くと、モジュールのほうが変数に隠されてしまいます。

私自身、動かないと相談を受けたコードを開いたら、ずっと上のほうにその一行が書かれていた、という経験があります。エラーメッセージを読んでも気づきにくい種類の事故です。

まとめと、次の一歩

覚えることは、そう多くありません。待つならsleep、測るならperf_counter。まずはこの2つで十分に戦えます。

sleepは最低の待ち時間を保証するもので、ぴったりでは戻ってこない。この性質さえ頭に置いておけば、精度で悩むこともなくなります。

一方で、毎朝決まった時刻に処理を動かしたいときは、sleepでずっと待たせるのではなく、OSの仕組みに任せるほうが確実です。【関連記事】Pythonで定期実行するには?cronとタスクスケジューラの基本

まずは手元のスクリプトを開いて、いちばん遅いと感じる処理をperf_counter()で挟んでみてください。数字が見えた瞬間から、改善は感覚の話ではなく具体的な作業に変わります。

ここまでお読みいただきありがとうございました。

参考情報

次のアクション

記事で学んだ内容を実際に動かしてみよう

Python WebAcademyでは、ブラウザ上でコードを書きながら基礎から実践まで体系的に学べます。

Python WebAcademyの学習画面

あわせて読む

関連記事

ブログ一覧へ

Python学習ロードマップ

まずはこの3講座から

記事で気になったテーマを、順番に手を動かしながら学べます。

ロードマップを見る