関数呼び出し vs forループ

Pythonで、関数呼び出しのオーバーヘッドとforループのオーバーヘッドを比較してみた。


import time

def foo(v):
# ここで、ある処理(A)
return v

r = range(10000000) # ここの個数を色々変える(B)

t1 = time.time()
p1 = [foo(v) for v in r]
t2 = time.time()
print 'time = ', t2 - t1 # => 4.9849998951

t3 = time.time()
p2 = []
for v in r:
# ここで、ある処理(A)
p2.append(v)
t4 = time.time()
print 'time = ', t4 - t3 # => 3.875


1つは、リスト内包表記の中で、関数を呼び出し処理(A)を実行し、もう1つは、forループで、処理(A)を直接埋め込んだ。
まず、(B)を色々変化させてみたが、rの個数が大きくなると、関数呼び出しの方が、若干早くなってくる。しかし、影響は無視できる程度だと思う。どうせ大差がつく前にメモリの限界が来ると思うので、ここでは、無視しておくことにする。
次に、(A)の処理を増やしてみた。すると、処理を増やすほど、関数呼び出しの方がforループに比べて劇的に早くなってくる。この理由は分からないが、簡単な式ならリスト内包表記の中にコードを埋め込む訳だし、複雑な式なら関数呼び出しの方が早くなってくる。


以上のテストからすると、通常の処理は十分複雑なので、forループを使うくらいなら、forループの中の処理Aをまとめて関数化し、リスト内包表記で呼び出す方が速くなる可能性が高い。
また、map()やfilter()などの関数よりリスト内包表記の方が(シーケンスの個数にもよると思うが)若干早いらしいので、なるべくならリスト内包表記を使用する方が良いと思われる。
しかし、コードの見易さはかなり重要なので、私なりの以下の結論を出してみた。



・なるべくリスト内包表記を使用する
・コードが読みにくくなる場合は、forループを使用する


しかし、引数の個数を増やすとかなり遅くなりそうなので、微妙であるが、通常は、それほど多く引数を渡すケースは少ないと思われる。
また、プリミティブなデータしか使用していないので、ユーザ定義のデータを使用するとどうなるかも不明。さらに、最適化やJITなども絡んでくるかもしれないので、結論を出すのは難しい。
全くもって、知識不足すぎるので、上記の結論が意味のあるものであるか不明…。単に、自分がプログラムを組むときのとりあえずの指針というだけの話。