クラス A があり、 というクラス A のインスタンスのリストがあるとしますlst
。
リスト内のすべてのインスタンスで、クラス Aの特定のメソッドm
を何百万回も何百万回も呼び出したいとします (実際の例:entity.update()
ゲームループ内のメソッド)。これを行う簡単な方法は次のとおりです。
for obj in lst: obj.m()
しかし、そのようなコードは私たちを眠らせます。そこでmap
、次のような使い方を考えます。
map(lambda obj: obj.m(), lst)
for
しかし、上記のコード行でいくつかの時間テストを実行すると、単純なループよりもはるかに遅いことがわかりました。場合によっては 2 倍も遅くなることがあります。map
次に、「すべての関数呼び出しの戻り値のリストを構築し、そのリストを返すため、おそらく遅い」と考えます。
と呼ばれる怠惰でメモリ効率の高い組み込み関数からインスピレーションを得たとしますxrange
。ほとんどの場合、これは のよりクールなバージョンだと思いますrange
。そのため、戻り値のリストを作成してそれを返すことなくxmap
、単にオブジェクトのリストに関数を適用するという関数を定義します。実装は次のとおりです。
def xmap(func, lst):
for obj in lst: func(obj)
for
この関数は上記のループを実行するだけなので非常にクールです。これは完璧な妥協だと思います。しかし、細心の注意を払っているので、2 つのスクリプトを作成してコードの速度をテストし、実際に よりも速くなったかどうかを確認することにしましたmap
。
最初のスクリプトはmap
、必要のないリストを単純に使用して無用に作成します。
script1.py
:
class A:
def m(self):
pass
lst = [A() for i in xrange(15)]
import time
start = time.time()
for i in xrange(1000000):
map(lambda obj: obj.m(), lst)
print time.time()-start, 'seconds'
2 番目のスクリプトは を使用xmap
しますが、15 の戻り値のリストを 1,000,000 回作成して返す必要がないため、より高速になると考えています。
script2.py
def xmap(func, lst):
for obj in lst: func(obj)
class A:
def m(self):
pass
lst = [A() for i in xrange(15)]
import time
start = time.time()
for i in xrange(1000000):
xmap(lambda obj: obj.m(), lst)
print time.time()-start, 'seconds'
最後に、コードがどれだけ高速になるかを見るのが楽しみです。ただし、両方のスクリプトを相互に数回実行した後、script2.py
は よりも速くないように見えることがわかりましscript1.py
た。実際には、script2.py
実行に よりもさらに時間がかかる場合がありますscript1.py
。xmap
とほぼ同じ時間がかかるようmap
です。
なぜこれらの結果が得られたのですか?
C:\dev\py>python script1.py
14.7799999714 seconds
C:\dev\py>python script2.py
14.2170000076 seconds
C:\dev\py>python script1.py
12.1800000668 seconds
C:\dev\py>python script2.py
12.5759999752 seconds
C:\dev\py>python script1.py
14.3020000458 seconds
C:\dev\py>python script2.py
14.9490001202 seconds
C:\dev\py>python script1.py
14.6879999638 seconds
C:\dev\py>python script2.py
14.3139998913 seconds
戻り値のリストを構築していなかったので、少なくとも何かを最適化しmap
たと思いましたが、私のコードはそれ以上高速ではないようです。私は次のことを行ったので、リストの構築に時間がかかることを知っています。
>>> import timeit
>>> timeit.timeit('[]')
0.1297345953932106
>>> timeit.timeit('[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]')
0.6807682686160632
>>> timeit.timeit('[None,None,None,None,None,None,None,None,None,None,None,None,
None,None,None]')
0.7460120889200539
では、なぜ私のxmap
関数は よりも速くないように見えるのmap
でしょうか?