Estoy tratando de comprender el rendimiento de una función de generador. He utilizado cProfile y el módulo pstats para recopilar e inspeccionar datos de creación de perfiles. La función en cuestión es la siguiente:Función del generador Rendimiento
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
es una cadena de texto Unicode, self.stringEnd
es un diccionario con 4 simples de expresiones regulares, self.patt es una gran expresión regular. Todo es dividir la cuerda grande en cuerdas más pequeñas, una por una.
perfilar un programa que utiliza He encontrado que la mayor parte del tiempo de ejecución del programa se gasta en esta función:
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__)
Pero mirando el perfil de la función en sí, no hay mucho tiempo dedicado en la sub-llamadas de funciones:
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}
el resto de la función no es mucho, además, mientras que las tareas y si-si no. Incluso el método send
en el generador que yo uso es rápido:
ncalls tottime percall cumtime percall filename:lineno(function)
13643/10835 0.007 0.000 11.552 0.001 {method 'send' of 'generator' objects}
¿Es posible que el yield
, pasando un valor de vuelta al consumidor, se está llevando a la mayoría de las veces ?! ¿Algo más de lo que no estoy enterado?
EDITAR:
probablemente debería haber mencionado que la función de generador de __iter__
es un método de una clase pequeña, por lo self
se refiere a una instancia de esta clase.
¿Qué tan grande es inData? Cortarlo repetidamente puede no ser muy eficiente. Tal vez si intentaras usar islice en itertools en su lugar. Ve si eso hace alguna diferencia. – Dunes
@Dunes Gracias, lo intentaré. Los datos de rendimiento se tomaron en una cadena de aproximadamente 1 MB. - Si pones esto en una respuesta, podría volver a votarlo. – ThomasH
¿Has probado [esto] (http://stackoverflow.com/questions/4295799/how-to-improve-performance-of-this-code/4299378#4299378)? –