我想了解发电机功能的性能。我已经使用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
是一个unicode字符串,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,assignments和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
指的是这个类的一个实例。
inData有多大?反复切片可能效率不高。也许如果你尝试在itertools中使用islice。看看这是否有所作为。 – Dunes 2011-06-08 20:45:20
@Dunes谢谢,会尝试。性能数据采用大约1MB的字符串。 - 如果你把这个答案放在答案中,我可以放弃它。 – ThomasH 2011-06-08 21:01:59
你有没有试过[this](http://stackoverflow.com/questions/4295799/how-to-improve-performance-of-this-code/4299378#4299378)? – 2011-06-09 04:13:22