Project Eulerや他のコーディングコンテストは、多くの場合、最大の実行時間があるか、または特定のソリューションの実行速度を誇っています。 pythonでは、時々アプローチがややぎこちなくなります - つまり、タイミングコードを__main__
に追加します。
Pythonプログラムの実行にかかる時間をプロファイルするのに良い方法は何ですか?
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 というタイトルのPyCon 2013の優れたビデオリソースへのリンクを更新。
またYouTube経由で 。
しばらく前に私はあなたのPythonコードから視覚化を生成する pycallgraph
を作りました。 編集: この執筆時点での最新リリースである3.3で動作するように例を更新しました。
pip install pycallgraph
をインストールして GraphViz をインストールした後は、コマンドラインから実行できます。
pycallgraph graphviz -- ./mypythonscript.py
または、コードの特定の部分をプロファイルすることもできます。
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput
with PyCallGraph(output=GraphvizOutput()):
code_to_profile()
どちらも下の画像のようなpycallgraph.png
ファイルを生成します。
プロファイラーの使用は(デフォルトでは)メインスレッドでのみ機能することを指摘しておく価値があります。それらを使用しても、他のスレッドから情報を取得することはできません。 profilerのドキュメント に完全には記載されていないので、これはちょっとした問題かもしれません。
スレッドのプロファイルも作成したい場合は、docsの 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
クラスを使用してください。それはあなたにもっと柔軟性を与えるかもしれません、しかし私はそれがそれが価値があるかどうか、特にあなたがあなたのクラスを使わないであろう第三者のコードを使っているならば。
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を必ずインストールしてください。
Sudo apt-get install python-profiler
ファイルに出力すると、以下のツールを使って素敵な視覚化を得ることができます。
PyCallGraph:コールグラフ画像を作成するためのツール
インストール:
Sudo pip install pycallgraph
実行します。
pycallgraph mine.py args
ビュー:
gimp pycallgraph.png
あなたはあなたがpngファイルを見るために好きなものを使うことができます、私はgimpを使いました
残念ながら私はよく
dot:graphはcairo-rendererのビットマップには大きすぎます。収まるように0.257079でスケーリング
これは私の画像が異常に小さくなります。だから私は一般的にSVGファイルを作成します。
pycallgraph -f svg -o pycallgraph.svg mine.py <args>
PS> graphvizをインストールしてください(これはドットプログラムを提供します):
Sudo pip install graphviz
@maxy/@quodlibetorによるgprof2dotを使った代替グラフ
Sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
この回答 に関する@ Maxyのコメントは、私がそれ自身の答えに値すると思うほど十分に私を助けてくれました:私はすでにcProfileで生成された.pstatsファイルを持っていました 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がより少ない情報を失うという印象を得る。
このトピックを調査したところ、 SnakeViz という便利なツールがありました。 SnakeVizはWebベースのプロファイリング視覚化ツールです。インストールと使用はとても簡単です。私が使う通常の方法は、%prun
を使ってstatファイルを生成してからSnakeVizで分析することです。
使用される主な技術は、以下に示すように、 サンバーストチャート です。ここで、関数呼び出しの階層は、角度の幅でエンコードされた円弧と時間情報の層として配置されます。
一番いいのはチャートと対話できることです。たとえば、ズームインするには弧をクリックします。弧とその子孫が新しいサンバーストとして拡大され、詳細が表示されます。
cProfile
はプロファイリングに最適で、 kcachegrind
は結果を視覚化するには最適だと思います。 pyprof2calltree
の間にあるファイル変換を処理します。
python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree
必要なツールをインストールするには(少なくともUbuntuでは):
apt-get install kcachegrind
pip install pyprof2calltree
結果:
GUI cProfile dump viewer RunSnakeRun も言及する価値があります。それはあなたがソートして選択することを可能にし、それによってプログラムの関連部分にズームインします。写真内の長方形のサイズは、かかる時間に比例します。四角形の上にマウスを置くと、テーブル内とマップ上のいたるところでその呼び出しが強調表示されます。四角形をダブルクリックすると、その部分が拡大されます。それは誰がその部分を呼ぶのか、そしてその部分が何を呼ぶのかをあなたに示すでしょう。
説明的な情報はとても役に立ちます。それはあなたに組み込みのライブラリ呼び出しを扱っているときに役立つことができるそのビットのためのコードを示します。どのファイルとどの行でコードを見つけるかがわかります。
また、OPが「プロファイリング」と言ったことを指摘したいのですが、彼は「タイミング」を意味していたようです。プロファイルを作成すると、プログラムの実行速度が遅くなります。
Niceプロファイリングモジュールはline_profilerです(スクリプトkernprof.pyを使って呼び出されます)。ダウンロードできます ここ 。
私の理解するところでは、cProfileは各機能に費やされた合計時間に関する情報だけを提供します。そのため、個々のコード行はタイミングが取られません。 1つの行に多くの時間がかかることがあるため、これは科学計算における問題です。また、私が覚えているように、cProfileは私がnumpy.dotで言っていた時間を捉えていませんでした。
最も簡単な そして 最も速い 常に進行中の場所を見つける方法。
1. pip install snakeviz
2. python -m cProfile -o temp.dat <PROGRAM>.py
3. snakeviz temp.dat
ブラウザで円グラフを描画します。最大のものは問題関数です。とても簡単です。
line_profiler
(すでにここに表示されています)は pprofile
にも影響を与えました。
細分性、スレッド対応の確定的および統計的純粋pythonプロファイラ
これは、line_profiler
のような細かさを提供し、純粋なPythonであり、スタンドアロンのコマンドまたはモジュールとして使用でき、[k|q]cachegrind
を使用して簡単に分析できるcallgrind形式のファイルも生成できます。
vprof もあります。これは、次のように記述されたPythonパッケージです。
[...]実行時間やメモリ使用量などのPythonプログラムのさまざまな特性について、豊富でインタラクティブな視覚化を提供します。
私は最近Pythonランタイムとインポートプロファイルを視覚化するために tuna を作成しました。これはここで役に立つかもしれません。
と一緒にインストール
pip3 install tuna
ランタイムプロファイルを作成する
python -mcProfile -o program.prof yourfile.py
またはインポートプロファイル(Python 3.7以降が必要)
python -X importprofile yourfile.py 2> import.log
それからそのファイルに対してtunaを実行してください。
tuna program.prof
たくさんの素晴らしい答えがありますが、それらは結果のプロファイリングやソートのためにコマンドラインか何らかの外部プログラムを使います。
コマンドラインに手を加えたり、何かをインストールしたりせずに、IDE(Eclipse-PyDev)で使用できる方法を本当に逃しました。だからここにあります。
def count():
from math import sqrt
for x in range(10**5):
sqrt(x)
if __== '__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)
詳細については docs または他の回答を参照してください。
マルチスレッドコードが期待どおりに動作しないというJoe Shawの回答に続いて、cProfileのruncall
メソッドは単にプロファイルされた関数呼び出しの周囲でself.enable()
およびself.disable()
の呼び出しを行っているだけであると考えました。 - 既存のコードとの干渉を最小限に抑えます。
Virtaalの source には(特定のメソッドや関数の場合でも)プロファイリングを非常に簡単にすることができる非常に便利なクラスとデコレータがあります。出力はKCacheGrindでとても快適に見ることができます。
cProfileは迅速なプロファイリングには最適ですが、ほとんどの場合はエラーで終了していました。関数runctxは環境と変数を正しく初期化することでこの問題を解決します。誰かに役立つことを願います:
import cProfile
cProfile.runctx('foo()', None, locals())
私のやり方はyappi( https://code.google.com/p/yappi/ )を使うことです。プロファイリング情報を開始、停止、および印刷するためのメソッドを登録するRPCサーバーと組み合わせると(デバッグだけでも)特に便利です。この方法では:
@staticmethod
def startProfiler():
yappi.start()
@staticmethod
def stopProfiler():
yappi.stop()
@staticmethod
def printProfiler():
stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
statPrint = '\n'
namesArr = [len(str(stat[0])) for stat in stats.func_stats]
log.debug("namesArr %s", str(namesArr))
maxNameLen = max(namesArr)
log.debug("maxNameLen: %s", maxNameLen)
for stat in stats.func_stats:
nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
log.debug('nameAppendSpaces: %s', nameAppendSpaces)
blankSpace = ''
for space in nameAppendSpaces:
blankSpace += space
log.debug("adding spaces: %s", len(nameAppendSpaces))
statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"
log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
log.log(1000, statPrint)
その後、プログラムが動作したら、startProfiler
RPCメソッドを呼び出してプロファイラを起動し、printProfiler
を呼び出してプロファイリング情報をログファイルにダンプし(または呼び出し元に返すようにrpcメソッドを変更する)、次のような出力を取得できます。
2014-02-19 16:32:24,128-|SVR-MAIN |-(Thread-3 )-Level 1000:
name ncall ttot tsub
2014-02-19 16:32:24,128-|SVR-MAIN |-(Thread-3 )-Level 1000:
C:\Python27\lib\sched.py.run:80 22 0.11 0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293 22 0.11 0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515 22 0.11 0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66 1 0.0 0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243 4 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4 0.0 0.0
<string>.__new__:8 220 0.0 0.0
C:\Python27\lib\socket.py.close:276 4 0.0 0.0
C:\Python27\lib\threading.py.__init__:558 1 0.0 0.0
<string>.__new__:8 4 0.0 0.0
C:\Python27\lib\threading.py.notify:372 1 0.0 0.0
C:\Python27\lib\rfc822.py.getheader:285 4 0.0 0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301 1 0.0 0.0
C:\Python27\lib\xmlrpclib.py.end:816 3 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467 1 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460 1 0.0 0.0
C:\Python27\lib\SocketServer.py.close_request:475 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\__init__.py.cpu_times:1066 4 0.0 0.0
短いスクリプトにはあまり便利ではないかもしれませんが、特にprintProfiler
メソッドが時間をかけて何度も呼び出されてプロファイルと比較を行うことができる場合は、サーバータイプのプロセスを最適化するのに役立ちます。さまざまなプログラム使用シナリオ.
Pythonでプロファイリングを処理するための新しいツールはPyVmMonitorです。 http://www.pyvmmonitor.com/
それはのようないくつかのユニークな機能を持っています
注:商用ですが、オープンソースは無料です。
それはあなたがプロファイリングから見たいものに依存するでしょう。単純な時間測定基準は(bash)で与えられます。
time python python_prog.py
'/ usr/bin/time'でも '--verbose'フラグを使用することで詳細なメトリックを出力できます。
各関数によって与えられた時間メトリックスをチェックし、関数にどのくらいの時間が費やされているかをよりよく理解するために、あなたはpythonの作り付けのcProfileを使うことができます。
パフォーマンスのようなより詳細な測定基準に入ると、時間だけが測定基準ではありません。あなたは、メモリ、スレッドなどについて心配することができます.
プロファイリングオプション:
1。 line_profiler は、タイミングメトリクスを1行ずつ見つけるために一般的に使用されるもう1つのプロファイラです。
2。 memory_profiler は、メモリ使用量をプロファイルするためのツールです。
3。 heapy(プロジェクトGuppyから) ヒープ内のオブジェクトの使用方法をプロファイルします。
これらは私が使いがちな共通のものです。しかし、もっと知りたいのなら、この本を読んでみてください。 book パフォーマンスを念頭に置いて始めてみると、かなりよい本です。 CythonとJIT(Just-In-Time)コンパイル済みPythonの使用に関する高度なトピックに進むことができます。
そのPythonスクリプトが何をしているのか知りたいと思ったことはありませんか。検査シェルに入ります。 Inspect Shellでは、実行中のスクリプトを中断することなく、グローバルを印刷/変更して関数を実行できます。オートコンプリートとコマンド履歴付き(Linuxのみ)。
Inspect Shellはpdbスタイルのデバッガではありません。
https://github.com/amoffat/Inspect-Shell
あなたはそれ(そしてあなたの腕時計)を使うことができます。
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 も参照してください。
statprof
という統計的プロファイラもあります。これはサンプリングプロファイラなので、コードに最小限のオーバーヘッドを追加し、(関数だけではなく)行ベースのタイミングを提供します。ゲームのようなソフトリアルタイムアプリケーションには適していますが、cProfileよりも精度が低い場合があります。
pypiのバージョン は少し古いので、 gitリポジトリ を指定することでpip
を付けてインストールできます。
pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01
このように実行することができます:
import statprof
with statprof.profile():
my_questionable_function()
https://stackoverflow.com/a/10333592/320036 も参照してください。
私がサーバーのルートになっていないときは、 lsprofcalltree.py を使用し、次のようにプログラムを実行します。
python lsprofcalltree.py -o callgrind.1 test.py
それから、 qcachegrind のように、callgrind互換のソフトウェアでレポートを開くことができます。
これらの派手なUIがすべてインストールまたは実行に失敗した場合の端末専用(および最も単純な)ソリューション:cProfile
を完全に無視し、pyinstrument
に置き換えます。これは、実行直後に呼び出しのツリーを収集して表示します。
インストール:
$ pip install pyinstrument
プロファイルと表示結果:
$ python -m pyinstrument ./prog.py
Python2および3で動作します。
gprof2dot_magic
JupyterLabまたはJupyter NotebookでPythonステートメントをDOTグラフとしてプロファイルするgprof2dot
のマジック関数。
GitHubリポジトリ: https://github.com/mattijn/gprof2dot_magic
インストール
Pythonパッケージgprof2dot_magic
があることを確認してください。
pip install gprof2dot_magic
依存関係gprof2dot
およびgraphviz
もインストールされます
使用法
マジック機能を有効にするには、最初にgprof2dot_magic
モジュールをロードします
%load_ext gprof2dot_magic
そして、次のようなDOTグラフとして、ラインステートメントのプロファイルを作成します。
%gprof2dot print('hello world')