1

クラス 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.pyxmapとほぼ同じ時間がかかるよう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でしょうか?

4

2 に答える 2

3

map は C で実装され、C-loop-land で動作します。Python-loop-land で実行しています。

于 2013-09-25T01:03:50.640 に答える