Я пытаюсь понять производительность функции генератора. Я использовал 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
, передавая значение обратно потребителю, занимает большую часть времени ?! Что-нибудь еще, о чем я не знаю?
РЕДАКТИРОВАТЬ :
Вероятно, мне следовало упомянуть, что функция генератора __ iter __
является методом небольшого класса, поэтому self
относится к экземпляру этого класса.