Pythonの実行時間を高精度で計測する

Python 上でプログラムの実行時間を計測する方法は調べればたくさん掲載されていますが,どれが最も良い方法なんでしょうか.

一番簡単な方法で紹介されるのは大抵 time.time()time.perf_counter() を実行した時間差で計測するものですが,最大の懸念はその精度.私自身,正確なものを求められているわけではないですが,精度が高いに越したことはありません.

OS による粒度の違い

公式ドキュメントによると,Python 3.3 以前の Windows では time.clock() はマイクロ秒,time.time() は 1/60 秒の精度で,Unix では time.clock() は 1/100 秒,time.time() はそれ以上の精度らしいです.解釈が間違っていなければ Windows で実行するか macOS で実行するかによって使う関数を変えなければならないという...

どちらにしてもデフォルトでは CPU 時間で計測しないため,CPU 上の他のプロセスの干渉を受けるようです.また,Unix では time.clock() を使うと CPU 時間で計測できるようですが,さっき 1/100 秒って言ってなかったっけ?という感じです.

Python 3.3 以降では time.clock() が廃止され,後に説明する time.perf_counter()time.process_time() を使うことになります.

timeit ライブラリのメソッド

Python には関数を指定回数実行したときの時間を計測するために timeit ライブラリが用意されています.

  • 簡単な処理を複数回実行するときのためのメソッドとして用意されている
  • 実行回数を指定できる

関数での処理があまり多くないもの向けのような感じで書いてあるので,複雑な処理を行う関数に対して適用していいのかはわからず,実行回数 1 回だけのときに使うのもどうなんでしょう?

from timeit import timeit

def func():
    execute_something()

# 簡単な関数を 1,000,000 回実行
timeit(func, number=1000000)

time ライブラリのメソッド

Python 3.3 以降,time ライブラリに以下のメソッドが追加されました.

time.perf_counter()

  • 短時間を精細に取得できる
  • PC がスリープしている間を含む
  • float 型で返す

古いバージョンでは timeit.default_timer() として提供されていたようです.

time.process_time()

  • CPU 時間を取得する
  • プロセスが動いているときだけを含み,PC がスリープしているときは含まない
  • float 型で返す

更に,Python 3.7 以降では上記のメソッドが float で返していた値を int で返してくれるメソッドも追加されました.

  • time.perf_counter_ns()
  • time.process_time_ns()

どちらのメソッドもナノ秒で値を返します.ドキュメントだけではどちらが優れているのかいまいち読み取れませんが,実際に測ってみると time.perf_counter() のほうが精度が良いらしいです.ナノ秒で返していても分解能が一致しているわけではないのですね.

20ms 以上の精度を求めるなら「time.perf_counter()」,それ以下で良いなら「time.process_time()」 | 粉末@それは風のように (日記)

ちなみに,同様にして time.time() にも同バージョンから time.time_ns() が追加されています.

結論

ドキュメントには所謂 Unix 時間を取得する time.time() メソッドは 1 秒以下が正確でない場合があるとの記述があったので,精度を求めるのであれば time.perf_counter() 辺りがいいようです.