通常、私はシェルコマンドを使用しますtime
。私の目的は、データが小、中、大、または非常に大きいセットであるかどうか、どのくらいの時間とメモリ使用量になるかをテストすることです。
これを行うためのLinuxまたはPython用のツールはありますか?
回答:
見ていはtimeit、Pythonのプロファイラとpycallgraphを。また、「SnakeViz」に言及して、以下のコメントnikicc
を確認してください。これにより、プロファイリングデータのさらに別の視覚化が可能になります。
def test():
"""Stupid test function"""
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
# For Python>=3.5 one can also write:
print(timeit.timeit("test()", globals=locals()))
基本的に、Pythonコードを文字列パラメーターとして渡すことができ、指定された回数で実行され、実行時間を出力します。ドキュメントからの重要なビット:
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)
Timer
指定されたステートメント、セットアップ コード、 タイマー関数を使用してインスタンスを 作成し、そのtimeit
メソッドを 数回実行して実行します。オプションのglobals引数は、コードを実行する名前空間を指定します。
...そして:
Timer.timeit(number=1000000)
時間数のメイン文の実行。これにより、セットアップステートメントが1回実行され、次にメインステートメントの実行にかかる時間がfloatとして秒単位で測定されて返されます。引数はループを通過する回数であり、デフォルトは100万回です。使用するmainステートメント、setupステートメント、timer関数がコンストラクターに渡されます。注: デフォルトでは、タイミング中に
timeit
一時的にオフgarbage collection
になります。このアプローチの利点は、独立したタイミングをより比較できるようにすることです。この欠点は、GCが測定される機能のパフォーマンスの重要な要素である可能性があることです。その場合、セットアップ文字列の最初のステートメントとしてGCを再度有効にすることができます。例えば:
timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()
プロファイリングはあなたを与えるだろうくらいに何が起こっているのかについてのより詳細なアイデアを。これが公式ドキュメントの「インスタント例」です。
import cProfile
import re
cProfile.run('re.compile("foo|bar")')
それはあなたに与えるでしょう:
197 function calls (192 primitive calls) in 0.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.001 0.001 <string>:1(<module>)
1 0.000 0.000 0.001 0.001 re.py:212(compile)
1 0.000 0.000 0.001 0.001 re.py:268(_compile)
1 0.000 0.000 0.000 0.000 sre_compile.py:172(_compile_charset)
1 0.000 0.000 0.000 0.000 sre_compile.py:201(_optimize_charset)
4 0.000 0.000 0.000 0.000 sre_compile.py:25(_identityfunction)
3/1 0.000 0.000 0.000 0.000 sre_compile.py:33(_compile)
これらのモジュールは両方とも、ボトルネックを探す場所についてのアイデアを提供するはずです。
また、の出力を把握するにはprofile
、この投稿をご覧ください
注pycallgraphは、2018年2月から正式に廃止されました。2020年12月の時点では、Python3.6でまだ動作していました。PythonがプロファイリングAPIを公開する方法にコアの変更がない限り、それは有用なツールであり続けるはずです。
このモジュールはgraphvizを使用して、次のようなcallgraphを作成します。
どのパスが最も時間を使用したかを色で簡単に確認できます。pycallgraph APIを使用するか、パッケージ化されたスクリプトを使用して作成できます。
pycallgraph graphviz -- ./mypythonscript.py
ただし、オーバーヘッドはかなりのものです。そのため、すでに長時間実行されているプロセスの場合、グラフの作成には時間がかかることがあります。
シンプルなデコレータを使用して関数の時間を計ります
def st_time(func):
"""
st decorator to calculate the total time of a func
"""
def st_func(*args, **keyArgs):
t1 = time.time()
r = func(*args, **keyArgs)
t2 = time.time()
print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
return r
return st_func
timeit
私がこれを書いたように、モジュールは、遅いと奇妙でした。
def timereps(reps, func):
from time import time
start = time()
for i in range(0, reps):
func()
end = time()
return (end - start) / reps
例:
import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)
私にとって、それは言う:
python can do 40925 os.listdir('/') per second
これは原始的な種類のベンチマークですが、それで十分です。
私は通常、time ./script.py
どれくらいの時間がかかるかを簡単に確認します。ただし、少なくともデフォルトとしては、メモリは表示されません。/usr/bin/time -v ./script.py
メモリ使用量など、多くの情報を取得するために使用できます。
/usr/bin/time
との-v
オプションは、多くのディストリビューションのデフォルトとして使用することはできませんインストールする必要があります。sudo apt-get install time
debian、ubuntuなどでpacman -S time
。archlinux–
すべてのメモリニーズに対応するメモリプロファイラー。
https://pypi.python.org/pypi/memory_profiler
pipインストールを実行します。
pip install memory_profiler
ライブラリをインポートします。
import memory_profiler
プロファイルするアイテムにデコレータを追加します。
@profile
def my_func():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
del b
return a
if __name__ == '__main__':
my_func()
コードを実行します。
python -m memory_profiler example.py
出力を受け取ります:
Line # Mem usage Increment Line Contents
==============================================
3 @profile
4 5.97 MB 0.00 MB def my_func():
5 13.61 MB 7.64 MB a = [1] * (10 ** 6)
6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7)
7 13.61 MB -152.59 MB del b
8 13.61 MB 0.00 MB return a
例は、上記のリンク先のドキュメントからのものです。
インストールすると、noseはパス内のスクリプトになり、いくつかのpythonスクリプトを含むディレクトリで呼び出すことができます。
$: nosetests
これにより、現在のディレクトリ内のすべてのpythonファイルが検索され、テストとして認識される関数が実行されます。たとえば、名前にtest_という単語が含まれる関数がテストとして認識されます。
したがって、test_yourfunction.pyというPythonスクリプトを作成して、次のように記述できます。
$: cat > test_yourfunction.py
def test_smallinput():
yourfunction(smallinput)
def test_mediuminput():
yourfunction(mediuminput)
def test_largeinput():
yourfunction(largeinput)
次に、実行する必要があります
$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py
プロファイルファイルを読み取るには、次のPython行を使用します。
python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"
nose
ホットショットに依存しています。Python 2.5以降は維持されておらず、「特殊な使用のために」のみ保持されています
注意してくださいtimeit
非常に遅いです、ちょうど初期化する(または多分関数を実行する)ために私の中型プロセッサで12秒かかります。あなたはこの受け入れられた答えをテストすることができます
def test():
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second
time
代わりに使用する簡単なものの場合、PCでは結果が返されます0.0
import time
def test():
lst = []
for i in range(100):
lst.append(i)
t1 = time.time()
test()
result = time.time() - t1
print(result) # 0.000000xxxx
timeit
関数を何度も実行して、ノイズを平均化します。繰り返しの数はオプションです。Pythonでの実行時間のベンチマークまたはこの質問で受け入れられた回答の後半を参照してください。
snakeviz
cProfileのインタラクティブビューア
https://github.com/jiffyclub/snakeviz/
cProfileはhttps://stackoverflow.com/a/1593034/895245で言及され、snakevizはコメントで言及されましたが、私はそれをさらに強調したいと思いました。
cprofile
/を見ただけでプログラムのパフォーマンスをデバッグするのは非常に困難です。pstats
出力をが箱から出してすぐに機能ごとに合計できる回数しかできないためです。
ただし、一般的に本当に必要なのは、各呼び出しのスタックトレースを含むネストされたビューを表示して、実際に主要なボトルネックを簡単に見つけることです。
そして、これはまさにsnakevizがデフォルトの「つらら」ビューを介して提供するものです。
まず、cProfileデータをバイナリファイルにダンプする必要があります。次に、その上でsnakevizを実行できます。
pip install -u snakeviz
python -m cProfile -o results.prof myscript.py
snakeviz results.prof
これにより、ブラウザで開くことができるstdoutへのURLが出力されます。これには、次のような目的の出力が含まれています。
そして、次のことができます。
よりプロファイル指向の質問:Pythonスクリプトをどのようにプロファイルできますか?
timeitの定型コードを記述せず、結果を簡単に分析したくない場合は、benchmarkitを参照してください。また、以前の実行の履歴が保存されるため、開発の過程で同じ機能を簡単に比較できます。
# pip install benchmarkit
from benchmarkit import benchmark, benchmark_run
N = 10000
seq_list = list(range(N))
seq_set = set(range(N))
SAVE_PATH = '/tmp/benchmark_time.jsonl'
@benchmark(num_iters=100, save_params=True)
def search_in_list(num_items=N):
return num_items - 1 in seq_list
@benchmark(num_iters=100, save_params=True)
def search_in_set(num_items=N):
return num_items - 1 in seq_set
benchmark_results = benchmark_run(
[search_in_list, search_in_set],
SAVE_PATH,
comment='initial benchmark search',
)
ターミナルに出力し、最後の実行のデータを含む辞書のリストを返します。コマンドラインエントリポイントも利用できます。
変更N=1000000
して再実行した場合
python -m cProfile -o results.prof myscript.py
。を使用してファイルに保存するオプションもあります。oputputファイルは、非常にきれいと呼ばれるプログラムで、ブラウザで提示することができますSnakeViz使用してsnakeviz results.prof