pythonで高速化するときの自分用のメモ
基本的な心得とか
- 無駄な処理はしない。複雑な処理を書かない。
- 自作しない。自分で書くよりライブラリ使った方が速い場合が多い。
- HDDは糞。ディスクI/Oは減らすべき。sqlite3も必要ない場合はメモリ上で動かす。
よく参考にするサイト
あなたのPythonを爆速にする7つの方法
最近プロコン(プログラミング・コンテスト)をはじめました。 基本的にはアルゴリズム勝負なのですが、とにかく速度
並列化
高速化が目的の場合に一番手っ取り早いのが並列化。
pythonで高速化目的の並列化を行う場合はマルチスレッドではなく、マルチプロセスで動かすべき。pythonのマルチスレッドだと、同一コアで動作するのでマルチコアの優位性を生かせない。なので、CPUをぶん回していいなら断然マルチプロセス。
でも一番バグが発生しやすいのも並列化。以下のことを心がける。
- 並列化した実行プロセス同士は同期させない。同期させないような処理の分け方にしておく。
- どうしても同期が必要な場合は排他制御を行う。排他フリーの同期ロジックを思いついたって?安心してください、それは幻想です。
- どうしてもプロセス間でデータのやり取りが必要な場合はmultiprocessing.Queue()等を使う。自作はしない。ただし、プロセス間でデータをやり取りすると、pythonオブジェクトのpickle/unpickleが走るので巨大なデータをやり取りすると目に見えて遅くなる。
関数呼び出し
pythonはスクリプト言語なので関数呼び出しもそこそこ馬鹿にできないコストがかかる。
予めオブジェクトに入れておいて使い回すと結構速くなる。
測定結果(10回平均)
普通に呼び出す | オブジェクトに入れる |
0.49sec | 0.41sec |
100万回のループで0.08secも変わるし、導入もかなりイージー。
ループ処理が深い場所では積極的に使っていきたい。
自作Cライブラリ
どう頑張っても高速化できない場合は、処理が重い部分のみをCライブラリで自作する。
ただし、Cライブラリに頻繁にアクセスすると、その部分の変換コストがかかって逆に遅くなる。
<参考>配列内の最小値インデックスの取得をCライブラリで実装した例
サイズ | 標準ライブラリ | numpy | Cライブラリ |
---|---|---|---|
10000 | 0.0018sec | 0.00081sec | 0.041sec |
1000000 | 0.027sec | 0.0077sec | 0.265sec |
コメント