cProfileを使用してPythonコードをプロファイリングする方法

Pythonは最速の言語ではないかもしれませんが、多くの場合、十分に高速です。また、Pythonは、プログラマーの時間がCPU時間よりも重要な場合に理想的です。

とは言うものの、特定のPythonアプリが遅れている場合は、それを吸い上げる必要はありません。Pythonインタープリターのストックインストールに含まれているツールは、プログラムのどの部分が遅いかについての詳細なフィードバックを提供し、それらを高速化する方法についてのヒントを提供します。

cProfileの使用方法

このcProfileモジュールは、Pythonプログラムの実行時間に関する統計を収集します。アプリ全体から単一のステートメントまたは式まで、あらゆるものについてレポートできます。

これが使い方のおもちゃの例ですcProfile

def add(x、y):x + = str(y)return x def add_2(x、y):if y%20000 == 0:z = [] for q in range(0,400000):z.append( q)def main():a = [] for n in range(0,200000):add(a、n)add_2(a、n)if __name__ == '__ main __':import cProfile cProfile.run( 'main( ) ') 

この例では、アプリケーションのmain()関数を実行し、main()すべてのmain()呼び出しのパフォーマンスを分析します。プログラムの一部のみを分析することも可能です が、初心者の最も一般的な使用法は、プログラム全体のプロファイルを作成することです。

上記の例を実行すると、次のような出力が表示されます。

ここに示されているのは、プログラムによって行われたすべての関数呼び出しのリストと、それぞれに関する統計です。

  • 上部(青色の最初の行)には、プロファイルされたプログラムで行われた呼び出しの総数と合計実行時間が表示されます。また、非再帰的な呼び出しを意味する「プリミティブ呼び出し」、または呼び出しスタックのさらに下の方に自分自身を呼び出さない関数に対して直接行われた呼び出しの図が表示される場合もあります。
  • ncalls:行われた呼び出しの数。スラッシュで区切られた2つの数値が表示されている場合、2番目の数値はその関数のプリミティブ呼び出しの数です。
  • tottime:他の関数への呼び出しを含まない、関数で費やされた合計時間。
  • percall:のためのコールあたりの平均時間tottime取ることで得られる、tottimeをしててそれを割るncalls
  • cumtime:他の関数の呼び出しを含む、関数で費やされた合計時間。
  • percall(#2):cumtimeの呼び出しごとの平均時間(cumtimeをncallsで割ったもの)。
  • filename:lineno:問題の呼び出しのファイル名、行番号、および関数名。

cProfileレポートを変更する方法

デフォルトではcProfile、出力を「標準名」で並べ替えます。つまり、右端の列のテキスト(ファイル名、行番号など)で並べ替えます。

デフォルトの形式は、参照用にすべての関数呼び出しの一般的なトップダウンレポートが必要な場合に役立ちます。ただし、ボトルネックの根底に到達しようとしている場合は、プログラムの最も時間のかかる部分を最初にリストする必要があります。

cProfile 少し異なる方法で呼び出すことで、これらの結果を生成でき ます。上記のプログラムの下部を作り直して、統計を別の列(この場合ncalls)で並べ替える方法に注意してください。

if __name__ == '__ main __':import cProfile、pstats profiler = cProfile.Profile()profiler.enable()main()profiler.disable()stats = pstats.Stats(profiler).sort_stats( 'ncalls')stats.print_stats () 

結果は次のようになります。

これがどのように機能するかを次に示します。

  • 代わりの方法でコマンドを実行するのcProfile.run()は非常に柔軟ではない、我々はプロファイリング作成したオブジェクトをprofiler
  • アクションを.enable()プロファイリングする場合は、最初にプロファイラーオブジェクトインスタンスを呼び出し、次にアクションを実行してから、を呼び出します.disable()。(これは、プログラムの一部のみをプ​​ロファイリングする1つの方法です。)
  • このpstatsモジュールは、プロファイラーオブジェクトによって収集された結果を操作し、それらの結果を出力するために使用されます。

プロファイラーオブジェクトを組み合わせてpstats、キャプチャされたプロファイルデータを操作できるようにします。たとえば、生成された統計を別の方法で並べ替えることができます。この例では、を使用し.sort_stats('ncalls')て統計をncalls列で並べ替えます。他のソートオプションが利用可能です。

最適化のためにcProfileの結果を使用する方法

cProfile 出力に使用できる並べ替えオプションを使用すると、プログラムの潜在的なパフォーマンスのボトルネックを取り除くことができます。

ncalls

発掘できる最初の最も重要な情報cProfileは、ncalls列を介して最も頻繁に呼び出される関数です。

Pythonでは、関数呼び出しを行うという単なる行為には、比較的大きなオーバーヘッドが発生します。一部の関数がタイトループで繰り返し呼び出されると、それが長時間実行される関数でなくても、パフォーマンスに影響を与えることが保証されます。

上記の例では、関数add(および関数add_2)がループ内で繰り返し呼び出されます。ループをadd関数自体に移動するか、add関数を完全にインライン化すると、この問題が修正されます。

tottime

プログラムを機能させるもう1つの有用な統計の詳細は、tottime列を介して実行にほとんどの時間を費やします。

上記の例では、add_2関数はループを使用して高価な計算をシミュレートし、tottimeスコアを一番上に押し上げています。tottimeスコアが高い関数は、特に何度も呼び出されたり、タイトなループで呼び出されたりする場合は、よく見る価値があります。

 関数が使用されるコンテキストを常に考慮する必要があることに注意してください。関数の値が高いtottimeが、一度だけ呼び出される場合(たとえば、プログラムの起動時のみ)、ボトルネックになる可能性は低くなります。ただし、起動時間を短縮しようとしている場合は、起動時に呼び出された関数が他のすべてを待機させているかどうかを知りたいと思うでしょう。

cProfileデータをエクスポートする方法

あなたが使用したい場合cProfileの、より高度な方法で生成された統計情報を、データファイルにエクスポートすることができます:

stats = pstats.Stats(profiler) stats.dump_stats('/path/to/stats_file.dat') 

This file can be read back in by using the pstats module, then sorted or displayed with pstats. The data can also be re-used by other programs. Two examples:

  • pyprof2calltree renders detailed visualizations of the program’s call graph and usage stats from profile data. This article provides a detailed real-world example of its use.
  • snakeviz also generates visualizations from cProfile data, but uses a different representation for the data — a “sunburst” rather than pyprof2calltree’s “flame” graph.

Beyond cProfile for Python profiling

cProfile is hardly the only way to profile a Python application. cProfile is certainly one of the most convenient ways, given that it’s bundled with Python. But others deserve attention.

1つのプロジェクトはpy-spy、呼び出しアクティビティをサンプリングすることにより、Pythonアプリケーションのプロファイルを作成します。py-spy実行中のPythonアプリを停止して再起動したり、コードベースを変更したりすることなく調べることができるため、デプロイされたアプリケーションのプロファイルを作成するために使用できます。py-spyまた、Pythonランタイムによって発生するオーバーヘッド(ガベージコレクションのオーバーヘッドなど)に関する統計も生成されますが、生成されcProfileません。