1521

Project Eulerやその他のコーディング コンテストでは、多くの場合、実行に最大の時間がかかったり、特定のソリューションの実行速度を自慢したりします。Python では、タイミング コードを .xml ファイルに追加するなど、アプローチがややぎこちない場合があります__main__

Python プログラムの実行にかかる時間をプロファイリングする良い方法は何ですか?

4

31 に答える 31

1590

Python にはcProfileというプロファイラーが含まれています。合計実行時間を提供するだけでなく、各関数を個別に計測し、各関数が呼び出された回数を示して、最適化を行う必要がある場所を簡単に判断できるようにします。

次のように、コード内から、またはインタープリターから呼び出すことができます。

import cProfile
cProfile.run('foo()')

さらに便利なことに、スクリプトの実行時に cProfile を呼び出すことができます。

python -m cProfile myscript.py

さらに簡単にするために、'profile.bat' という小さなバッチ ファイルを作成しました。

python -m cProfile %1

だから私がしなければならないのは実行することだけです:

profile euler048.py

そして、私はこれを取得します:

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

編集: Python Profiling
Also via YouTubeというタイトルの PyCon 2013 からの優れたビデオ リソースへのリンクを更新 しました。

于 2009-02-24T16:01:40.570 に答える
487

少し前にpycallgraph、Python コードからビジュアライゼーションを生成するものを作成しました。編集:この記事の執筆時点での最新リリースである 3.3 で動作するように例を更新しました。

GraphVizpip install pycallgraphをインストールした後、コマンド ラインから実行できます。

pycallgraph graphviz -- ./mypythonscript.py

または、コードの特定の部分をプロファイリングできます。

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

pycallgraph.pngこれらのいずれかで、以下の画像のようなファイルが生成されます。

ここに画像の説明を入力

于 2012-08-06T05:37:07.207 に答える
223

プロファイラーの使用は (既定では) メイン スレッドでのみ機能し、他のスレッドを使用しても、他のスレッドからは情報を取得できないことに注意してください。これは、プロファイラーのドキュメントではまったく言及されていないため、ちょっとした問題になる可能性があります。

スレッドのプロファイリングも行いたい場合は、ドキュメントのthreading.setprofile()関数を参照してください。

threading.Thread独自のサブクラスを作成してそれを行うこともできます。

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

ProfiledThread標準のクラスの代わりにそのクラスを使用します。柔軟性が向上する可能性がありますが、特にクラスを使用しないサードパーティのコードを使用している場合は、それだけの価値があるかどうかはわかりません。

于 2009-12-17T16:30:34.247 に答える
170

python wiki はリソースのプロファイリングに最適なページです: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

pythonドキュメントと同様: http://docs.python.org/library/profile.html

Chris Lawlor が示すように、cProfile は優れたツールであり、画面への印刷に簡単に使用できます。

python -m cProfile -s time mine.py <args>

またはファイルする:

python -m cProfile -o output.file mine.py <args>

PS> Ubuntu を使用している場合は、必ず python-profile をインストールしてください。

apt-get install python-profiler 

ファイルに出力する場合、次のツールを使用して素敵な視覚化を取得できます

PyCallGraph : コール グラフ イメージを作成するツール
インストール:

 pip install pycallgraph

走る:

 pycallgraph mine.py args

見る:

 gimp pycallgraph.png

pngファイルを表示するには、好きなものを使用できます.gimpを使用しました
残念ながら、よく取得します

ドット: cairo-renderer ビットマップに対してグラフが大きすぎます。適合するように 0.257079 でスケーリング

これにより、画像が使用できないほど小さくなります。だから私は一般的にsvgファイルを作成します:

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS> graphviz (dot プログラムを提供する) を必ずインストールしてください:

pip install graphviz

@maxy / @quodlibetor 経由で gprof2dot を使用した代替グラフ:

pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
于 2011-10-08T00:04:12.983 に答える
149

この回答に対する@Maxyのコメントは、それが独自の回答に値すると思うほど十分に役立ちました.cProfileで生成された.pstatsファイルが既にあり、pycallgraphで再実行したくなかったので、 gprof2dot を使用、きれいになりましたsvg:

$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg

そしてブラム!

ドット (pycallgraph が使用するものと同じもの) を使用するため、出力は似ています。ただし、gprof2dot が失う情報が少ないという印象を受けます。

gprof2dot の出力例

于 2012-12-11T23:16:39.907 に答える
43

また、言及する価値があるのは、GUI cProfile ダンプ ビューアーRunSnakeRunです。並べ替えと選択ができるため、プログラムの関連部分を拡大できます。写真の長方形のサイズは、所要時間に比例します。長方形の上にマウスを置くと、その呼び出しがテーブルとマップ上のすべての場所で強調表示されます。長方形をダブルクリックすると、その部分が拡大されます。誰がその部分を呼び出し、その部分が何を呼び出すかが表示されます。

説明的な情報は非常に役立ちます。組み込みのライブラリ呼び出しを扱うときに役立つ、そのビットのコードが表示されます。コードを検索するファイルと行がわかります。

また、OPが「プロファイリング」と言ったことを指摘したいのですが、彼は「タイミング」を意味していたようです。プロファイリングすると、プログラムの実行が遅くなることに注意してください。

ここに画像の説明を入力

于 2015-02-22T16:18:05.447 に答える
36

優れたプロファイリングモジュールはline_profilerです(スクリプトkernprof.pyを使用して呼び出されます)。こちらからダウンロードできます。

私の理解では、cProfileは各関数で費やされた合計時間に関する情報のみを提供します。したがって、コードの個々の行のタイミングは調整されません。多くの場合、1つの行に多くの時間がかかる可能性があるため、これは科学計算の問題です。また、私が覚えているように、cProfileは私がnumpy.dotと言って過ごしていた時間を捕らえませんでした。

于 2011-10-20T16:05:34.820 に答える
36

pprofile

line_profilerpprofile(すでにここに示されています)また、次のように説明されている に触発 されました。

行粒度、スレッド対応の決定論的および統計的な純粋な Python プロファイラー

line_profilerは純粋な Python であり、スタンドアロン コマンドまたはモジュールとして使用でき、さらには で簡単に分析できる callgrind 形式のファイルを生成できます[k|q]cachegrind

vprof

次のように説明されている Python パッケージであるvprofもあります。

[...] 実行時間やメモリ使用量など、さまざまな Python プログラムの特性について、豊富でインタラクティブな視覚化を提供します。

ヒートマップ

于 2015-03-02T11:36:47.300 に答える
20

多くの優れた回答がありますが、それらはコマンドラインまたは外部プログラムを使用して、結果のプロファイリングおよび/または並べ替えを行います。

コマンドラインに触れたり、何もインストールしたりせずに、IDE(eclipse-PyDev)で使用できる方法を本当に見逃していました。それで、ここにあります。

コマンドラインを使用しないプロファイリング

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __name__ == '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

詳細については、ドキュメントまたはその他の回答を参照してください。

于 2015-08-21T11:59:43.567 に答える
13

マルチスレッド コードが期待どおりに動作しないという Joe Shaw の回答に続いてruncall、cProfile のメソッドはプロファイルされた関数呼び出しを実行して呼び出すself.enable()だけであると考えました。self.disable()既存のコードへの干渉を最小限に抑えます。

于 2011-11-09T12:59:04.463 に答える
10

Virtaal のソースには、プロファイリング (特定のメソッド/関数であっても) を非常に簡単にできる非常に便利なクラスとデコレータがあります。出力は、KCacheGrind で非常に快適に表示できます。

于 2009-02-24T20:31:10.237 に答える
5

https://stackoverflow.com/a/582337/1070617に追加するには、

cProfile を使用してその出力を簡単に表示できるようにするこのモジュールを作成しました。詳細はこちら: https://github.com/ymichael/cprofilev

$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.

収集された統計を理解する方法については、 http : //ymichael.com/2014/03/08/profiling-python-with-cprofile.htmlも参照してください。

于 2015-03-21T13:50:12.133 に答える
5

pypref_time からインスピレーションを得て、独自のプロファイラーを開発しました。

https://github.com/modaresimr/auto_profiler

デコレータを追加することで、時間のかかる関数のツリーが表示されます

@Profiler(depth=4, on_disable=show)

Install by: pip install auto_profiler

import time # line number 1
import random

from auto_profiler import Profiler, Tree

def f1():
    mysleep(.6+random.random())

def mysleep(t):
    time.sleep(t)

def fact(i):
    f1()
    if(i==1):
        return 1
    return i*fact(i-1)


def show(p):
    print('Time   [Hits * PerHit] Function name [Called from] [Function Location]\n'+\
          '-----------------------------------------------------------------------')
    print(Tree(p.root, threshold=0.5))
    
@Profiler(depth=4, on_disable=show)
def main():
    for i in range(5):
        f1()

    fact(3)


if __name__ == '__main__':
    main()

出力例


Time   [Hits * PerHit] Function name [Called from] [function location]
-----------------------------------------------------------------------
8.974s [1 * 8.974]  main  [auto-profiler/profiler.py:267]  [/test/t2.py:30]
├── 5.954s [5 * 1.191]  f1  [/test/t2.py:34]  [/test/t2.py:14]
│   └── 5.954s [5 * 1.191]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
│       └── 5.954s [5 * 1.191]  <time.sleep>
|
|
|   # The rest is for the example recursive function call fact
└── 3.020s [1 * 3.020]  fact  [/test/t2.py:36]  [/test/t2.py:20]
    ├── 0.849s [1 * 0.849]  f1  [/test/t2.py:21]  [/test/t2.py:14]
    │   └── 0.849s [1 * 0.849]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
    │       └── 0.849s [1 * 0.849]  <time.sleep>
    └── 2.171s [1 * 2.171]  fact  [/test/t2.py:24]  [/test/t2.py:20]
        ├── 1.552s [1 * 1.552]  f1  [/test/t2.py:21]  [/test/t2.py:14]
        │   └── 1.552s [1 * 1.552]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
        └── 0.619s [1 * 0.619]  fact  [/test/t2.py:24]  [/test/t2.py:20]
            └── 0.619s [1 * 0.619]  f1  [/test/t2.py:21]  [/test/t2.py:14]
于 2020-02-12T12:03:16.613 に答える
4

Python スクリプトが何をしているのか知りたいと思ったことはありませんか? 検査シェルに入ります。Inspect Shell を使用すると、実行中のスクリプトを中断することなく、グローバルを印刷/変更し、関数を実行できます。オートコンプリートとコマンド履歴が追加されました (Linux のみ)。

Inspect Shell は pdb スタイルのデバッガーではありません。

https://github.com/amoffat/Inspect-Shell

あなたはそれ(そしてあなたの腕時計)を使うことができます。

于 2012-10-13T15:21:22.260 に答える
1

cprofiler やその他のリソースは、デバッグよりも最適化を目的としていることがわかりました。

単純な Python スクリプトの速度テストの代わりに、独自のテスト モジュールを作成しました。(私の場合、1,000 行以上の py ファイルが ScriptProfilerPy を使用してテストされ、その後数分でコードが 10 倍高速化されました。

モジュール ScriptProfilerPy() は、タイムスタンプを追加してコードを実行します。ここにモジュールを配置します: https://github.com/Lucas-BLP/ScriptProfilerPy

使用する:

from speed_testpy import ScriptProfilerPy

ScriptProfilerPy("path_to_your_script_to_test.py").Profiler()

出力: テスト後のコードの出力

于 2022-01-11T10:27:09.547 に答える