もう笑うしかないときのPython〜実行速度編〜

どーも、色々詰んでる者です。
あんまり更新してないと、僕の現在状況を知っている人にあらぬ誤解を受けて捜索願を提出されてしまう恐れがあるので、どーでもいいネタでWebを汚してやろうと思います。
有り体に言うと、ただの八つ当たりです。


まあ、バカの馬鹿話はおいといて。


今回は、実行速度に関する、ちょっとした実験結果です。
背景にあるのは、ここでも何回か登場したPythonでWAVをどーたらこーたらの話なんですが、要点をかいつまんで話すと、Python遅くねぇ?』です。

さすがに、Cなら0.22秒でできることがPythonだと7.69秒かかるというのは、いくら仏様でも一度目でブチ切れます。
山羊、指令書食ってる場合じゃありません。


で。


当然、この無能の塊こと僕のコーディングですから、何かしら不備があるに決まっています。
そこで、何とか実行速度を上げたいという思いから、今回の実験を行ったわけです。


前置きはこの辺で。
本題に入りましょう。

2011/7/31 追記:

この記事が気になった方は、コメントも参照してください。

検証実験:

以下、testN(Nは0以上の整数)と記述されているものは、テストに用いたサンプルコードのtestN.pyを指します。
実験環境は、CPUはCore-i7、メモリ4GB、Ubuntu(64bit)です。
また、実行速度の計測はUNIX/Linuxのtimeコマンドを使いました。

appendとリスト内包表記:

test1とtest2は、リストの中身を別リストへ移す(コピーではない)プログラムです。実行速度はそれぞれ、test1が3.64秒、test2が2.29秒でした。


この結果より、可能な限りリスト内包表記を用いることが、速度向上に有益であると考えられます。

hex(ord())とbinascii.b2a_hex():

test3とtest4は、読み込んだバイナリデータをPythonで扱える形の16進数に変換しています。Pythonでは\x00形式がとんでもなく扱い辛いので、この実験を行いました。結果ですが、test3が6.40秒でtest4が7.92秒でした。


このことから、同じ結果を得るならhex()とord()を組み合わせた方が早いことが分かります。

list型とarray型:

test5はtest2との比較用プログラムで、要素の移し替えという点では同じです。結果、test5は5.31秒かかり、test2の2.29秒に遠く及びませんでした。


この結果から、array型の利用が速度向上には繋がらないと考えられます。

arrayのappendメソッドとextendメソッド:

test5ではarrayの要素追加にappendを使いましたが、test6ではextendを使います。extendのそもそもの使い方とは違いますが、一応の比較実験です。結果は、test5の5.31秒に対して、test6は15.99秒でした。


結論は言うまでもなく、appendの方がまだマシ、ということです。

arrayのappendメソッドと+メソッド:

test7では要素の追加に+を使っています。気になる実行速度ですが、何と12.43秒もかかり、appendを使っていたtest5の5.31秒の足元にも及びませんでした。


この結果から、どうあがいてもappend有利のようです。

リストと文字列:

test8はtest1と同じような操作ですが文字列への移し替えという点で異なります。結果ですが、test8が3.96秒でtest1の3.51秒、さらにtest2の2.29秒と比べると、速度的には劣ることが分かりました。

コピー元と同じ長さのリストを作っておく:

test9はtest1と同様の処理を行いますが、コピー元となるリストと同じ長さのリストを作っておくという工程が入ります。移す際も、要素の入れ替えとなります。結果、test9は4.67秒でした。


ただ、こっちのほうが早くなった例があるそうで、何だかよく分からない結果になってしまいました。

テストに使ったサンプルコード:

### all
# sample.wav: 44.1kHz, mono, 16bit
# 3:56.17=10415232samples(by SoX)
def load():
        fp=open("sample.wav","rb")
        tmp=fp.read()
        fp.close()
        return tmp
raw=load()

### test1.py
txt=[]
for i in raw:
        txt.append(i)
print len(txt),len(raw),txt[0],raw[0]

### test2.py
txt=[i for i in raw]
print len(txt),len(raw),txt[0],raw[0]

### test3.py
txt=[hex(ord(i)) for i in raw]
print len(txt),txt[0:30]

### test4
import binascii
txt=["0x"+binascii.b2a_hex(i) for i in raw]
print len(txt),txt[0:30]

### test5
import array
a=array.array("c")
for i in raw:
    a.append(i)
print len(a),len(raw),a[0],raw[0]

### test6.py
import array
a=array.array("c")
for i in raw:
    a.extend(i)
print len(a),len(raw),a[0],raw[0]

### test7.py
import array
a=array.array("c")
for i in raw:
    a+=array.array("c",i)
print len(a),len(raw),a[0],raw[0]

### test8.py
txt=""
for i in raw:
        txt+=i
print len(txt),len(raw),txt[0],raw[0]

### test9.py
txt=range(len(raw))
for i,j in enumerate(raw):
        txt[i]=j
print len(txt),len(raw),txt[0],raw[0]

最後に:

まあ、ここまで散々やった挙句に、と言うか、散々やったために。
最近はC実装を検討しています。


だって、C早いんだもん……

まあ、世の中こんなもんです。
でも、Pythonは楽なので、今後も使いつづけてはいくと思います。
無論、趣味の領域で、ですが。

それでは、また〜。僕が生きていれば、ですが。