Python Language
パフォーマンスの最適化
サーチ…
備考
まず、Pythonスクリプトのパフォーマンスを向上させようとする場合、スクリプトのボトルネックを見つけ、最適化がデータ構造の貧弱な選択やアルゴリズム設計の欠陥を補うことができないことに注意してください。パフォーマンスのボトルネックを特定するには、スクリプトをプロファイリングすることができます。第二に、読みやすさ/デザイン/品質を犠牲にしてコーディングプロセスをあまりに早く最適化しようとしないでください。 Donald Knuthは最適化について次のように述べました。
「早期の最適化はすべての悪の根源であり、時間の約97%という小規模な効率性を忘れてはならない。しかし、我々はその重要な3%で機会を逃すべきではない」
コードプロファイリング
まず、スクリプトのボトルネックを見つけ、最適化がデータ構造の貧弱な選択やアルゴリズム設計の欠陥を補うことができないことに注意してください。第二に、読みやすさ/デザイン/品質を犠牲にしてコーディングプロセスをあまりに早く最適化しようとしないでください。 Donald Knuthは最適化について次のように述べました。
「早期の最適化はすべての悪の根源だが、97%程度の小さな効率を忘れてはならないが、その3%の重要な点で機会を逃してはならない」
コードをline_profiler
は、標準ライブラリであるline_profiler
とtimeit
cProfile
(またはより遅いprofile
)といういくつかのツールがありtimeit
。それぞれは異なる目的を果たします。
cProfile
は決定論的プロファイラです。関数呼び出し、関数の戻り値、および例外イベントが監視され、これらのイベントの間隔(0.001秒まで)に対して正確なタイミングが作成されます。ライブラリのドキュメント([ https://docs.python.org/2/library/profile.html] [1 ])は、簡単なユースケースを提供しています
import cProfile
def f(x):
return "42!"
cProfile.run('f(12)')
既存のコードの一部をラップしたい場合は、次のようにします。
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
# ... long ...
pr.disable()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
これにより、以下の表のような出力が作成されます。ここでは、プログラムがどこの時間を費やしているかを素早く見て、最適化する関数を特定できます。
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <stdin>:1(f)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
モジュールline_profiler
([ https://github.com/rkern/line_profiler] [1 ])は、コードを行line_profiler
分析するのに便利です。これは明らかに長いスクリプトでは管理できませんが、スニペットを対象としています。詳細は、ドキュメントを参照してください。最も簡単な方法は、kernprofスクリプトをパッケージページの説明に従って使用することです。プロファイルを作成するには、関数を手動で指定する必要があります。
$ kernprof -l script_to_profile.py
kernprofは、LineProfilerのインスタンスを作成し、それを名前プロファイルとともに__builtins__
名前空間に挿入します。これはデコレータとして使われるように書かれているので、スクリプトで@profile
プロファイルしたい関数を@profile
ます。
@profile
def slow_function(a, b, c):
...
kernprofのデフォルトの動作は、結果をバイナリファイルscript_to_profile.py.lprof
です。 kernprofに、[-v / - view]オプションを指定すると、端末でフォーマットされた結果をすぐに見ることができます。それ以外の場合は、結果を後で次のように表示できます。
$ python -m line_profiler script_to_profile.py.lprof
最後にtimeit
は、コマンドラインとPythonシェルの両方から1つのライナーまたは小さな式をテストする簡単な方法を提供します。このモジュールは、リストの理解を行うのが速いか、セットをリストに変換するときに組み込みlist()
使用する方が速いかなどの質問に答えます。セットアップコードを追加するには、 setup
キーワードまたは-s
オプションを探します。
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
端末から
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop