Я пытаюсь понять производительность функции генератора. Я использовал cProfile и модуль pstats для сбора и проверки данных профилирования. Рассматриваемая функция такова:
def __iter__(self):
delimiter = None
inData = self.inData
lenData = len(inData)
cursor = 0
while cursor < lenData:
if delimiter:
mo = self.stringEnd[delimiter].search(inData[cursor:])
else:
mo = self.patt.match(inData[cursor:])
if mo:
mo_lastgroup = mo.lastgroup
mstart = cursor
mend = mo.end()
cursor += mend
delimiter = (yield (mo_lastgroup, mo.group(mo_lastgroup), mstart, mend))
else:
raise SyntaxError("Unable to tokenize text starting with: \"%s\"" % inData[cursor:cursor+200])
self.inData
- текстовая строка в юникоде, self.stringEnd
- это диктант с 4 простыми регулярными выражениями, self.patt - это одно большое регулярное выражение. Все дело в том, чтобы разбить большую строку на более мелкие, одну за другой.
Профилирование программы, которая использует его. Я обнаружил, что большая часть времени выполнения программы тратится на эту функцию:
In [800]: st.print_stats("Scanner.py:124")
463263 function calls (448688 primitive calls) in 13.091 CPU seconds
Ordered by: cumulative time
List reduced from 231 to 1 due to restriction <'Scanner.py:124'>
ncalls tottime percall cumtime percall filename:lineno(function)
10835 11.465 0.001 11.534 0.001 Scanner.py:124(__iter__)
Но, глядя на профиль самой функции, не так много времени уходит на под-вызовы функций:
In [799]: st.print_callees("Scanner.py:124")
Ordered by: cumulative time
List reduced from 231 to 1 due to restriction <'Scanner.py:124'>
Function called...
ncalls tottime cumtime
Scanner.py:124(__iter__) -> 10834 0.006 0.006 {built-in method end}
10834 0.009 0.009 {built-in method group}
8028 0.030 0.030 {built-in method match}
2806 0.025 0.025 {built-in method search}
1 0.000 0.000 {len}
Остальная часть функции не очень похожа на while, присваивания и if-else. Даже метод send
на генераторе, который я использую, быстр:
ncalls tottime percall cumtime percall filename:lineno(function)
13643/10835 0.007 0.000 11.552 0.001 {method 'send' of 'generator' objects}
Возможно ли, что yield
, передавая значение обратно потребителю, отнимает большую часть времени ?! Что-нибудь еще, о чем я не знаю?
EDIT
Я, вероятно, должен был упомянуть, что функция генератора __iter__
является методом небольшого класса, поэтому self
относится к экземпляру этого класса.