[英]Generators vs List Comprehension performance in Python
目前我正在学习生成器和列表理解,并且弄乱了剖析器以查看性能增益,并且在这两个中使用两者中的大量素数的总和数量的混乱。
我可以在生成器中看到:1 genexpr作为累积时间方式比列表对应方式短,但第二行是令我感到困惑的。 正在做一个我认为是数字检查的电话是素数,但是不应该是另一个:列表理解中的1个模块?
我在个人资料中遗漏了什么吗?
In [8]: cProfile.run('sum((number for number in xrange(9999999) if number % 2 == 0))')
5000004 function calls in 1.111 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
5000001 0.760 0.000 0.760 0.000 <string>:1(<genexpr>)
1 0.000 0.000 1.111 1.111 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.351 0.351 1.111 1.111 {sum}
In [9]: cProfile.run('sum([number for number in xrange(9999999) if number % 2 == 0])')
3 function calls in 1.123 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 1.075 1.075 1.123 1.123 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.048 0.048 0.048 0.048 {sum}
首先调用生成器对象的next
(或Python 3中的__next__
)方法,而不是进行某些偶数检查。
在Python 2中,你不会为列表理解(LC)获得任何额外的行,因为LC没有创建任何对象,但是在Python 3中你将因为现在使它类似于生成器表达式而增加一个代码对象( <listcomp>
)也是为LC创建的。
>>> cProfile.run('sum([number for number in range(9999999) if number % 2 == 0])')
5 function calls in 1.751 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 1.601 1.601 1.601 1.601 <string>:1(<listcomp>)
1 0.068 0.068 1.751 1.751 <string>:1(<module>)
1 0.000 0.000 1.751 1.751 {built-in method exec}
1 0.082 0.082 0.082 0.082 {built-in method sum}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
>>> cProfile.run('sum((number for number in range(9999999) if number % 2 == 0))')
5000005 function calls in 2.388 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
5000001 1.873 0.000 1.873 0.000 <string>:1(<genexpr>)
1 0.000 0.000 2.388 2.388 <string>:1(<module>)
1 0.000 0.000 2.388 2.388 {built-in method exec}
1 0.515 0.515 2.388 2.388 {built-in method sum}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
虽然1(LC)与生成器表达式中的5000001相比调用次数不同,但这大部分是因为sum
消耗了迭代器,因此必须将其__next__
方法调用500000 + 1次(最后1可能是StopIteration
结束迭代) 。 对于列表理解,所有的魔法发生在其代码对象中,其中LIST_APPEND
帮助它LIST_APPEND
将项目附加到列表中,即没有可见的cProfile
调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.