カスタムイテレータを使用して小さなコンテナを反復処理するときに、かなり驚くべきパフォーマンスの違いに遭遇しています。私は、誰かが、これらの違いがどこから来ているのか理解するのを助けることができるかもしれないことを望んでいました。カスタムイテレータのパフォーマンス
最初にいくつかのコンテキストがあります。私はboost :: pythonを使っていくつかのPython拡張モジュールを書いています。そのうちの1つはgetitemを実装する3d floatベクトル型へのバインディングを含んでいます。しかし、それを反復することができるgetitemがありますが、かなり遅いですが、その理由はわかりません。なぜ単純なカスタムイテレータをPythonで使用して、どのように動作するかをよりよく理解することにしました。これらのイテレータがどこから来たのである...
class MyIterator1(object):
__slots__ = ['values', 'popfn']
def __init__(self):
self.values = ['x', 'y', 'z']
self.popfn = self.values.pop
def __length_hint__(self):
return 3
def __iter__(self):
return self
def next(self):
try:
return self.popfn()
except IndexError:
raise StopIteration
class MyIterator2(object):
__slots__ = ['values', 'itfn']
def __init__(self):
self.values = ['x', 'y', 'z']
it = iter(self.values)
self.itfn = it.next
def __length_hint__(self):
return 3
def __iter__(self):
return self
def next(self):
return self.itfn()
class MyIterator3(object):
__slots__ = ['values', 'i']
def __init__(self):
self.values = ['x', 'y', 'z']
self.i = 0
def __length_hint__(self):
return 3
def __iter__(self):
return self
def next(self):
if self.i >= 3:
raise StopIteration
value = self.values[self.i]
self.i += 1
return value
def MyIterator4():
val = ['x', 'y', 'z']
yield val[0]
yield val[1]
yield val[2]
次は私が
import timeit
timer1 = timeit.Timer('r = list(testiter.MyIterator1())', 'import testiter')
timer2 = timeit.Timer('r = list(testiter.MyIterator2())', 'import testiter')
timer3 = timeit.Timer('r = list(testiter.MyIterator3())', 'import testiter')
timer4 = timeit.Timer('r = list(testiter.MyIterator4())', 'import testiter')
timer5 = timeit.Timer('r = list(iter(["x", "y", "z"]))', 'import testiter')
print 'list(testiter.MyIterator1())'
print timer1.timeit()
print "\n"
print 'list(testiter.MyIterator2())'
print timer2.timeit()
print "\n"
print 'list(testiter.MyIterator3())'
print timer3.timeit()
print "\n"
print 'list(testiter.MyIterator4())'
print timer4.timeit()
print "\n"
print 'list(iter(["x", "y", "z"]))'
print timer5.timeit()
この印刷物(上記のコードは、モジュールと呼ばれるtestiter内にあるとみなされます)はtimeitモジュールでスクリプトを介してこれらのを走りました以下を外してください
list(testiter.MyIterator1())
8.5735929
list(testiter.MyIterator2())
5.28959393501
list(testiter.MyIterator3())
6.11230111122
list(testiter.MyIterator4())
2.31263613701
list(iter(["x", "y", "z"]))
1.26243281364
驚くべきことに、python listiteratorは、かなりのマージンで最も速いです。私は、これがpython内のいくつかの魔法の最適化に至ったと考えています。ジェネレータはMyIteratorクラスよりもかなり高速ですが、これもまた私は驚くことではありません。また、すべての作業がCで行われていることを前提としていますが、これは単なる推測です。今や他の人たちはもっと混乱し/賛成しています。 try/except文はこの文脈のように高価であるか、それとも何か他のことが起こっていますか?
これらの相違点を説明する助けがあれば、大歓迎です!長い投稿のための謝罪。
['x'、 'y'、 'z']の代わりにタプルを使用できます(可能な場合)。タプルの作成はリストのビットよりも少し速いです。 –