Pythonの高速化
高速化のコツ
ループ中での条件判断を避けたりなど、やりたいことの処理方法を少し検討するだけでも速度向上が得られることもあります。
numba や cython で高速化できる部分というのは演算処理の部分だけです。
メモリアクセスやディスクI/Oでのデータ読み込み待ちには殆ど効果がありません。
1回しか呼ばれない関数を10%高速化するより、100,000回呼ばれる関数を1%高速化するほうが全体としては性能向上となる場合があることを理解しましょう。
つまりボトルネックとなっている箇所と原因を理解したうえで、適切な対応をすることが重要です。 具体的な例
関数やオブジェクトを参照する.をできるだけ使用しないようにする
理由は、ドット(.)表記では内部的に辞書検索が発生していて、特にループ内部で繰り返し使われると影響が積み重なってゆくからです。
重要なことは非常に多くのループが行われる処理の中で.で毎回辞書検索させないことです。
ループ中でif文を使うと、当然のことながらループ回数だけ毎回条件判断が繰り返されてしまう
例外処理として扱うとこれを避けることができるようになる。
しかし可読性は下がる
優れたアルゴリズムを用いる
等比数列の足し算は公式を用いるなど
分岐処理をなくす改良を行う
Pythonでわかる!アルゴリズムと改良テクニック にて紹介されていた
高速化のなかでもネストを深くしすぎず、物事の本質をとらえるために使用する感じ
「把持を行う中で、ホームポジションを順番に変更したい」という課題があるとする。
code:py
# countは毎フレーム増加するものだとする。
# そのフレームごとに、listになったある処理列を順番に実行し続ける場合を考える。
count = 0
while True:
if count % 3 == 0:
# 初めの処理
if count % 3 == 1:
# 2番目の処理
if count % 3 == 2:
# 3番目の処理
# N番目で一般化できる。
# if count % 3 == N:
# # N番目の処理
# ↓ すべてを一緒くたにまとめてしまうことができる。
# これを行うと分岐が減ってpositionsが増えたときもpositionsを増やすだけでよくなる
# 代わりに可読性が下がる
count += 1
可読性との天秤にかけながら、どの実装がよいのか検討しよう
printをfor文の中で使用しないこと
printステートメントの有無によって、実行時間が60倍ほど異なる。
so i saved $27000/year by removing 10 lines of code this morning. they were print() statements.
「今朝10行のコードを削除して、年間27000ドル節約しました。print () 文でした。」
stdoutへの書き込みは信じられないほど遅く、非効率的です。
C/C++や他のほとんどの言語でこれを行うと、非常に似たベンチマークに遭遇するでしょう。
よってPythonだけでなくC由来の他の言語でも同じような問題が起こる
この問題はプログラミング言語ではなく、オペレーティングシステムに関係があります。
Printはシステムコールを実行し、システムの応答を待ちます。
対策:
printのみを処理する別のスレッドのキューにメッセージをプッシュすることで、はるかに高速にすることができます。
cv2.imwriteも非常に処理が遅い
同時にcv2.imwriteを消し忘れると死ぬほど遅くなることが知られている(それはそう)
printの問題と同じく、ファイルアクセスであり、システムコールを実行しシステムの応答を待たなくてはならないため非常に遅い。これは自分でもよく発生してしまう事項。