●Pythonで処理時間を計測する4つの方法
プログラムの処理時間を計測することは、コードの最適化やパフォーマンス改善に欠かせない作業です。
特に、大規模なシステムや複雑なアルゴリズムを扱う場合、少しの処理時間の差が大きな影響を与えることがあります。
Pythonには、処理時間を計測するためのさまざまなモジュールやテクニックが用意されています。
ここでは、初心者にもわかりやすく、すぐに実践できる4つの方法を紹介します。
○timeモジュールを使う
timeモジュールは、Pythonの標準ライブラリの1つで、時間に関する各種関数を提供しています。
処理時間の計測には、time()関数を使います。
□サンプルコード1:timeモジュールの基本的な使い方
このコードでは、time()関数を使って処理の開始時間と終了時間を取得し、その差分から経過時間を計算しています。
実行結果
この例では、単純なループ処理を1,000,000回実行するのに、約0.047秒かかったことがわかります。
□サンプルコード2:ミリ秒単位での計測
秒単位では詳細な計測ができない場合、ミリ秒単位で計測するのも1つの方法です。
timeモジュールのtime()関数は、デフォルトでは秒単位ですが、結果に1000を掛けることでミリ秒単位に変換できます。
実行結果
ループ回数を1,000回に減らしたため、ミリ秒単位でも計測できる程度の処理時間になりました。
timeモジュールは簡単に使えるため、手軽に処理時間を計測したい場合に適しています。
ただし、より詳細な計測や、平均実行時間の算出などが必要な場合は、後述するtimeitモジュールを使うのがおすすめです。
○datetimeモジュールを使う
timeモジュールでは秒単位やミリ秒単位での計測ができましたが、より詳細な時間管理が必要な場合はdatetimeモジュールを使うのがおすすめです。
datetimeモジュールでは、日付や時刻を表すdatetimeオブジェクトを使って、時間の計算や比較を行うことができます。
処理時間の計測には、datetime.now()関数を使います。
この関数は、現在の日時を表すdatetimeオブジェクトを返します。
□サンプルコード3:datetimeモジュールの基本的な使い方
実行結果
datetime.now()関数で取得した開始時間と終了時間の差分を計算することで、経過時間を求めています。
結果は、時:分:秒.マイクロ秒の形式で表示されます。
□サンプルコード4:経過時間の計算
datetimeオブジェクトは、時間の計算にも使えます。
たとえば、経過時間をより詳細に分析したい場合は、total_seconds()メソッドを使って秒単位の経過時間を取得できます。
実行結果
このように、total_seconds()メソッドを使えば、経過時間を秒単位で取得できます。
さらに、その結果に1000を掛けることでミリ秒単位に、1000000を掛けることでマイクロ秒単位に変換できます。
○timeitモジュールを使う
ここまで、timeモジュールとdatetimeモジュールを使った処理時間の計測方法を見てきましたが、実は、Pythonにはもっと便利なモジュールがあります。
それが、timeitモジュールです。
timeitモジュールは、小さなコード片の実行時間を測定するために設計されたモジュールで、特に、同じコードを複数回実行して平均実行時間を求めるのに便利です。
□サンプルコード5:timeitモジュールの基本的な使い方
実行結果
timeit.timeit()関数の第一引数には、実行時間を計測したいコードを文字列として渡します。
ここでは、100万回のループを実行するコードを渡しています。
第二引数のnumberは、コードを実行する回数を指定します。
デフォルトでは100万回の計測が行われますが、ここでは1回に設定しています。
□サンプルコード6:繰り返し実行による平均実行時間の計測
timeitモジュールの真価は、同じコードを複数回実行して平均実行時間を求める場合に発揮されます。
たとえば、先ほどのコードを10回実行して平均実行時間を求めてみましょう。
実行結果
number=10と指定することで、コードを10回実行し、その合計実行時間を求めています。
その結果を10で割ることで、平均実行時間を計算しています。
○デコレータを使う
最後に紹介するのは、デコレータを使った処理時間の計測方法です。
デコレータは、関数やメソッドの前後に処理を追加するための機能で、Pythonの強力な機能の1つです。
処理時間の計測にデコレータを使うと、計測したい関数やメソッドを修正することなく、簡単に計測を行うことができます。
まずは、デコレータの基本的な使い方から見ていきましょう。
□サンプルコード7:デコレータの基本的な使い方
デコレータは、関数を引数に取り、新しい関数を返す関数です。
ここでは、my_decorator
という名前のデコレータを定義しています。
デコレータの内部では、wrapper
という関数を定義し、元の関数を呼び出す前後に処理を追加しています。
*args
と**kwargs
は、元の関数に渡された引数をそのままwrapper
関数に渡すための記法です。
@my_decorator
という記法を使って、my_function
関数にデコレータを適用しています。
これにより、my_function
関数が呼び出される前後に、デコレータ内の処理が実行されます。
□サンプルコード8:デコレータを使った処理時間の計測
それでは、デコレータを使って処理時間を計測してみましょう。
実行結果
measure_time
デコレータの内部では、time
モジュールを使って処理時間を計測しています。
計測したい関数に@measure_time
デコレータを付けるだけで、関数の実行時間を計測することができます。
func.__name__
は、デコレータが適用された関数の名前を取得するための記法です。
これを使うことで、どの関数の実行時間を計測したのかを出力することができます。
デコレータを使った処理時間の計測は、コードの修正が少なくて済むため、既存のコードに手軽に計測機能を追加することができます。
また、デコレータを使えば、計測以外にもさまざまな処理を関数の前後に追加することができます。
ただし、デコレータを使いすぎると、コードの可読性が下がる可能性がある点には注意が必要です。
適度な使用にとどめ、コードの意図が伝わりやすいようにしましょう。
●計測時の注意点
ここまで、PythonでCPU時間を計測するさまざまな方法を見てきました。
しかし、正確な計測を行うためには、いくつか注意点があります。
ここでは、計測時に気をつけるべきポイントを3つ紹介します。
○sleepを使ったウェイト処理
処理時間を計測する際、計測対象のコードにsleep関数を使ったウェイト処理が含まれていると、計測結果が大きく影響を受けます。
たとえば、次のようなコードがあったとします。
実行結果
my_function
内で1秒間のウェイト処理が行われているため、計測結果は1秒以上になっています。
しかし、このウェイト処理は、実際の処理時間とは関係ありません。
したがって、処理時間を正確に計測するためには、計測対象のコードからsleep関数を使ったウェイト処理を取り除く必要があります。
○計測環境による誤差
処理時間の計測結果は、計測環境によって大きく異なる可能性があります。
たとえば、次のような要因が計測結果に影響を与える可能性があります。
- マシンのスペック(CPU、メモリ、ストレージなど)
- OSやPythonのバージョン
- バックグラウンドで動作しているプロセス
- 計測時の負荷状況
特に、バックグラウンドで重い処理が動作している場合、計測結果が大きく影響を受ける可能性があります。
したがって、処理時間の計測は、できるだけ同じ環境で行うことが重要です。
また、複数回の計測を行い、平均値を取るなどの工夫も必要でしょう。
○計測対象の適切な選択
処理時間を計測する際は、計測対象を適切に選ぶ必要があります。
たとえば、次のようなコードがあったとします。
実行結果
このコードでは、my_function
を10回呼び出しています。
しかし、my_function
内の処理時間のほとんどは、sleep関数によるウェイト処理が占めています。
本当に計測したいのは、for
ループの処理時間だったはずです。
しかし、計測結果は、ウェイト処理の時間に大きく影響されてしまっています。
したがって、処理時間を計測する際は、計測対象を適切に選ぶ必要があります。
計測したい処理に集中し、不要な処理は計測対象から外しましょう。
●処理時間計測の活用例
処理時間の計測は、単に時間を測るだけではなく、プログラムの改善に役立てることが重要です。
ここでは、処理時間計測の具体的な活用例を3つ紹介します。
○ボトルネックの特定
プログラムの処理速度が遅い場合、まずは処理時間の計測を行い、ボトルネックを特定することが重要です。
ボトルネックとは、プログラム全体の処理速度を律速している部分のことを指します。
たとえば、次のようなコードがあったとします。
実行結果
このコードでは、load_data
、process_data
、save_data
の3つの関数が順番に呼び出されています。
計測結果から、load_data
関数の処理時間が最も長いことがわかります。
つまり、load_data
関数がボトルネックになっていると考えられます。
このような場合は、load_data
関数の処理を最適化することで、プログラム全体の処理速度を改善できる可能性があります。
○アルゴリズムの比較
処理時間の計測は、異なるアルゴリズムの性能比較にも役立ちます。
たとえば、ソートアルゴリズムを比較する場合、次のようなコードを書くことができます。
実行結果
このコードでは、バブルソートとクイックソートの処理時間を比較しています。
計測結果から、クイックソートの方が圧倒的に高速であることがわかります。
このように、処理時間の計測を行うことで、アルゴリズムの性能差を定量的に評価することができます。
より高速なアルゴリズムを選択することで、プログラムの処理速度を大幅に改善できる可能性があります。
○パフォーマンス改善の評価
処理時間の計測は、パフォーマンス改善の効果を評価するためにも役立ちます。
たとえば、次のようなコードがあったとします。
実行結果
このコードでは、process_data
関数で大量のデータを処理しています。
ここで、処理速度を改善するために、リスト内包表記を使って書き換えてみます。
実行結果
リスト内包表記を使うことで、処理時間がほぼ半分になりました。
このように、処理時間の計測を行うことで、パフォーマンス改善の効果を定量的に評価することができます。
まとめ
本記事では、Pythonでプログラムの処理時間を計測する方法を4つ紹介しました。
Pythonでの処理時間の計測は、プログラムの最適化やデバッグに欠かせない技術です。
本記事で紹介した方法を参考に、ぜひ自分のプログラムの処理時間を計測してみてください。
処理時間の計測は、一見地味な作業かもしれません。
しかし、その一手間が、プログラムの性能を大きく左右する可能性があります。
効率的なプログラムを書くためには、処理時間の計測を習慣づけ、常に改善を心がけることが大切だと私は考えています。
本記事が、みなさんのPythonプログラミングのスキルアップの一助となれば幸いです。