Tre*_*reg 10 python performance profiling set
在分析我的Python应用程序时,我发现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");
Run Code Online (Sandbox Code Playgroud)
根据profiler的统计数据,lenA()似乎比lenB()以下慢14倍:
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)
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?目前我使用__len__()而不是len(),但代码看起来很脏:(
Fre*_*Foo 17
显然,len有一些开销,因为它执行函数调用并转换AttributeError为TypeError.此外,这set.__len__是一个简单的操作,与几乎任何东西相比,它必然会非常快,但在使用时我仍然找不到像14x差异的东西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
Run Code Online (Sandbox Code Playgroud)
你应该总是打电话len,而不是__len__.如果调用len是程序中的瓶颈,则应重新考虑其设计,例如某处的高速缓存大小,或者在不调用的情况下计算它们len.
这是关于探查器的有趣观察,它与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}
Run Code Online (Sandbox Code Playgroud)
...虽然只有一行涉及lenB:
1 0.273 0.273 0.273 0.273 .../lentest.py:9(lenB)
Run Code Online (Sandbox Code Playgroud)
探查器已对从lenA到的每个调用len计时,但lenB总体上计时。定时呼叫总是会增加一些开销。对于lenA,您会看到此开销乘以一百万倍。