Python 3中len(set)与set._len__;()的评测性能
在分析Python的应用程序时,我发现使用set时,Python 3中len(set)与set._len__;()的评测性能,python,performance,profiling,set,Python,Performance,Profiling,Set,在分析Python的应用程序时,我发现使用set时,len()似乎是一个非常昂贵的应用程序。请参阅以下代码: import cProfile def lenA(s): for i in range(1000000): len(s); def lenB(s): for i in range(1000000): s.__len__(); def main(): s = set(); lenA(s); lenB(s); i
len()
似乎是一个非常昂贵的应用程序。请参阅以下代码:
import cProfile
def lenA(s):
for i in range(1000000):
len(s);
def lenB(s):
for i in range(1000000):
s.__len__();
def main():
s = set();
lenA(s);
lenB(s);
if __name__ == "__main__":
cProfile.run("main()","stats");
根据下面探查器的统计数据,lenA()
似乎比lenB()慢14倍:
我错过什么了吗?目前我使用\uuu len\uuu()
而不是len()
,但代码看起来很脏:(显然,len
有一些开销,因为它执行函数调用,并将AttributeError
转换为TypeError
。此外,设置。len\uuuuuuu
是一个非常简单的操作,与几乎任何东西相比,它肯定会非常快,但我在使用时仍然没有发现14倍的差异timeit
:
In [1]: s = set()
In [2]: %timeit s.__len__()
1000000 loops, best of 3: 197 ns per loop
In [3]: %timeit len(s)
10000000 loops, best of 3: 130 ns per loop
你应该总是调用len
,而不是\uuu len
。如果对len
的调用是你程序中的瓶颈,你应该重新考虑它的设计,例如在某处缓存大小,或者在不调用len的情况下计算它们。这将是一个评论,但在larsman对他有争议的结果和结果发表评论之后根据我得到的结果,我认为将我的数据添加到线程中是很有趣的
尝试或多或少相同的设置我得到了相反的OP得到了,并且在相同的方向上由larsman评论:
12.1964105975 <- __len__
6.22144670823 <- len()
C:\Python26\programas>
这是win7中的activepython 2.6.7 64位。这是关于探查器的一个有趣的观察,它与len函数的实际性能无关。您可以看到,在探查器统计信息中,有两行内容涉及到lenA
:
ncalls tottime percall cumtime percall filename:lineno(function)
1 1.986 1.986 3.830 3.830 .../lentest.py:5(lenA)
1000000 1.845 0.000 1.845 0.000 {built-in method len}
…虽然只有一行关于lenB
:
ncalls tottime percall cumtime percall filename:lineno(function)
1 1.986 1.986 3.830 3.830 .../lentest.py:5(lenA)
1000000 1.845 0.000 1.845 0.000 {built-in method len}
1 0.273 0.273 0.273 0.273 .../lentest.py:9(lenB)
1 0.273 0.273 0.273 0.273 .../lentest.py:9(lenB)
探查器已将每个调用从lenA
计时到len
,但将lenB
作为一个整体计时。对调用计时总是会增加一些开销;在lenA的情况下,您会看到此开销成倍增加。为什么要使用cProfile
而不是timeit
?前者用于查找瓶颈在大型程序中,它会牺牲一些小规模上的准确性。后者用于相对精确地测量微小片段的总体性能。timeit
应该是这样的微基准的首选。对我来说,它表明了一个不太极端的差异(每len
调用0.0879µs,每调用0.158µs,每调用0.158µs,比len
慢70%)。谢谢@delnan,我是Python新手。使用timeit
我也得到了类似的比率。的确,我的程序比上面的代码大得多,但是len()
函数似乎是主要的瓶颈之一。好的,所以我将忽略len()
并关注我自己的功能,对吗?+1:特别是不要过早优化。基准可能有缺陷,正如您现在可能看到的,三个基准可能会返回三个不同的结果;您可能会使用这样一个微基准来测试与您预期完全不同的东西。显然,len
不能更快,因为它调用\uuuu len\uuuuu
。但这是肯定的。@Anony Mouse:事实上,我只是再次查看了我自己的结果,我现在才看到len
比\uuu len\uuuuu
快。不确定这是怎么发生的。s.\uu len uuuuuu
也进行函数调用,并且必须查找属性。thatt大于len
@FredFoo:len()的全局查找
不必查找内置类型的\uuuu leng\uuu
。事实上,它从不直接查找\uuu leng\uuu
。它将tp\u作为\u序列
指针查找,遍历到该结构的sq\u length
属性。自定义Python类通过查找\uu leng\uu
属性填充该插槽。对于 设置
和
列表
这样,就不需要最后一步了。我认为你的观点绝对准确。这都是关于cProfile
的开销,而不是len
函数的性能。
1 0.273 0.273 0.273 0.273 .../lentest.py:9(lenB)