✈️

[実行時間]プログラム内のボトルネック特定

2023/07/02に公開

PythonのcProfileはプロファイラモジュールの一つで、プログラムの実行時間を解析し、どの関数がどれだけの時間を消費しているかを詳細に把握することができます。プロファイリングを使用してパフォーマンスのボトルネックを特定し、必要な最適化を行うことができます。

cProfileモジュールはPythonの標準ライブラリの一部であり、Cで実装されているため高速に動作します。それはプログラム全体、または特定の関数やメソッドのプロファイリングを行うことができます。

以下に、cProfileの基本的な使い方を示します。

まず、プロファイリングしたいPythonのスクリプトがあるとします。例えば、以下のようなスクリプトです:

# slow_code.py

import time

def slow_function():
    time.sleep(2)

def fast_function():
    time.sleep(0.1)

if __name__ == "__main__":
    slow_function()
    fast_function()

このスクリプトをcProfileでプロファイリングするには、以下のようにコマンドラインから実行します:

python -m cProfile slow_code.py

これを実行すると、以下のような出力が得られます:

         67 function calls in 2.104 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    2.104    2.104 slow_code.py:1(<module>)
        1    0.000    0.000    2.002    2.002 slow_code.py:4(slow_function)
        1    0.000    0.000    0.102    0.102 slow_code.py:8(fast_function)
        2    2.104    1.052    2.104    1.052 {built-in method time.sleep}
       60    0.000    0.000    0.000    0.000 {method 'acquire' of '_thread.lock' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

この出力の各行は、プロファイリングされたスクリプトの各関数に対応しています。各列は以下の意味を持ちます:

  • ncalls: 関数が呼び出された回数
  • tottime: 関数が実行に費やした合計時間(他の関数の呼び出し時間を除く)
  • percall: 関数呼び出しの平均時間(tottime / ncalls
  • cumtime: 関数が実行に費やした合計時間(他の関数の呼び出し時間を含む)
  • percall: 関数呼び出しの平

均時間(cumtime / ncalls

  • filename:lineno(function): 関数の名前と、その関数の定義があるファイルと行番号

この情報を使って、コードのどの部分が最も時間を消費しているかを特定し、それに基づいて最適化を行うことができます。

また、cProfileはプログラム内から直接呼び出すことも可能で、特定のコードブロックのプロファイリングに便利です:

import cProfile

def some_function():
    # 何か時間のかかる処理
    pass

profiler = cProfile.Profile()
profiler.enable()

# プロファイリングを開始
some_function()

profiler.disable()
profiler.print_stats()

このコードは、some_functionの実行中に発生するすべての関数呼び出しをプロファイリングします。enableメソッドでプロファイリングを開始し、disableメソッドで終了します。最後に、print_statsメソッドを使って結果を表示します。

Discussion