プログラミング/python の履歴(No.3)

更新


公開メモ

プロファイリング

python は普通に書くと思った以上に遅いことになる場合が多いので、 プロファイリングの結果を基に重い処理を numpy 側に移したりするのが役に立つ

いろいろ試した結果、特に並列処理を使ったバッチ処理が走るライブラリを使う場合には jupyter 上でのプロファイリングするとライブラリ関数の実行中に UI スレッドが動いて プロファイル結果が無茶苦茶になるようです。

したがって面倒でもプロファイルは Jupyter 外で行った方が間違いない。

前処理結果を dump する

jupyter 上で計算した結果を引き継ぎつつ jupyter 外で処理を回すには、前処理で得られたデータ(プロファイリングしたい処理への入力)を pickle.dump しておき、外部で動かす処理ではそれを呼んで動作を行う

Jupyter セル内で実行

LANG:python
import pickle
payload = {
    "param1": param1,
    "param2": param2,
    "param3": param3,
}
with open("payload.pkl", "wb") as f:
    pickle.dump(payload, f, protocol=pickle.HIGHEST?PROTOCOL)

で(通常の python データであれば)書き出せる

読み込んで動かす .py ファイル

do_profile.py

LANG:python
import pickle
import cProfile
import pstats

from my_module import func_to_profile

def main():
    with open("payload.pkl", "rb") as f:
        payload = pickle.load(f)

    prof = cProfile.Profile()
    prof.enable()
    refined = func_to_profile(**payload)
    prof.disable()

    prof.dump_stats("prof.out")

if __name__ == "__main__":
    main()

実行する

LANG:console
$ python do_profile.py

解析する

LANG:console
$ python -m pstats prof.out
Welcome to the profile statistics browser.
prof.out% strip        # strip directory names
prof.out% sort cumtime # sort by cumtime
prof.out% stats 40     # show first 40 items

これで、

my_module.py:1234(my_function)

みたいな関数ごとに

LANG:console
ncalls   tottime  percall  cumtime  percall filename:lineno(function)
呼び出し 自前処理 呼び出し 子も含む 呼び出し ファイル名:行番号(関数名)
回数     時間     あたり   全時間   あたり

のリストが出ます

特定の関数内から呼ばれている分だけを調べたければ、

LANG:console
prof.out% sort time
prof.out% callees my_module.py:1234(my_function)

などとします。


Counter: 456 (from 2010/06/03), today: 2, yesterday: 4