Python 为什么这个lambda函数比for循环版本更慢?
我在写一篇关于python编码风格的博客文章时,遇到了一些我觉得很奇怪的事情,我想知道是否有人理解了它到底是怎么回事。基本上,我有两个相同功能的版本:Python 为什么这个lambda函数比for循环版本更慢?,python,performance,lambda,lazy-evaluation,Python,Performance,Lambda,Lazy Evaluation,我在写一篇关于python编码风格的博客文章时,遇到了一些我觉得很奇怪的事情,我想知道是否有人理解了它到底是怎么回事。基本上,我有两个相同功能的版本: a = lambda x: (i for i in range(x)) def b(x): for i in range(x): yield i 我想比较一下这两种方法的性能。在我看来,这应该包括一个可以忽略不计的计算量,而且两种方法都应该非常接近于零,然而,当我实际运行timeit时: def timing(x, nu
a = lambda x: (i for i in range(x))
def b(x):
for i in range(x):
yield i
我想比较一下这两种方法的性能。在我看来,这应该包括一个可以忽略不计的计算量,而且两种方法都应该非常接近于零,然而,当我实际运行timeit时:
def timing(x, number=10):
implicit = timeit.timeit('a(%s)' % int(x), 'from __main__ import a', number=number)
explicit = timeit.timeit('b(%s)' % int(x), 'from __main__ import b', number=number)
return (implicit, explicit)
def plot_timings(*args, **kwargs):
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
x_vector = np.linspace(*args, **kwargs)
timings = np.vectorize(timing)(x_vector)
ax.plot(x_vector, timings[0], 'b--')
ax.plot(x_vector, timings[1], 'r--')
ax.set_yscale('log')
plt.show()
plot_timings(1, 1000000, 20)
我发现这两种方法之间存在巨大差异,如下所示:
a为蓝色,b
为红色“>
其中a
为蓝色,b
为红色
为什么差异如此之大?看起来显式for循环版本也在以对数增长,而隐式版本什么都不做(这是应该的)
有什么想法吗?差异是由
range
a
在构建范围时需要调用它。b
在第一次迭代之前不需要调用range
>>> def myrange(n):
... print "myrange(%s)"%n
... return range(n)
...
>>> a = lambda x: (i for i in myrange(x))
>>> def b(x):
... for i in myrange(x):
... yield i
...
>>> a(100)
myrange(100)
range(100)
<generator object <genexpr> at 0xd62d70>
>>> b(100)
<generator object b at 0xdadb90>
>>> next(_) # <-- first iteration of b(100)
myrange(100)
range(100)
0
>>def myrange(n):
…打印“myrange(%s)”%n
…返回范围(n)
...
>>>a=λx:(i代表我的范围内的i(x))
>>>def b(x):
…对于我的范围内的i(x):
…让我
...
>>>a(100)
myrange(100)
射程(100)
>>>b(100)
>>>下一个()#lambda调用是慢速调用。请查看以下内容:
import cProfile
a = lambda x: (i for i in range(x))
def b(x):
for i in range(x):
yield i
def c(x):
for i in xrange(x):
yield i
def d(x):
i = 0
while i < x:
yield i
i += 1
N = 100000
print " -- a --"
cProfile.run("""
for x in xrange(%i):
a(x)
""" % N)
print " -- b --"
cProfile.run("""
for x in xrange(%i):
b(x)
""" % N)
print " -- c --"
cProfile.run("""
for x in xrange(%i):
c(x)
""" % N)
print " -- d --"
cProfile.run("""
for x in xrange(%i):
d(x)
""" % N)
print " -- a (again) --"
cProfile.run("""
for x in xrange(%i):
a(x)
""" % N)
导入cProfile
a=λx:(范围(x)内i的i)
def b(x):
对于范围(x)内的i:
产量一
def c(x):
对于x范围内的i(x):
产量一
定义d(x):
i=0
而i
给出了以下结果:
-- a --
300002 function calls in 61.764 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 30.881 30.881 61.764 61.764 <string>:3(<module>)
100000 0.051 0.000 0.051 0.000 test.py:5(<genexpr>)
100000 0.247 0.000 30.832 0.000 test.py:5(<lambda>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
100000 30.585 0.000 30.585 0.000 {range}
-- b --
100002 function calls in 0.076 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.066 0.066 0.076 0.076 <string>:3(<module>)
100000 0.010 0.000 0.010 0.000 test.py:7(b)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
-- c --
100002 function calls in 0.075 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.065 0.065 0.075 0.075 <string>:3(<module>)
100000 0.010 0.000 0.010 0.000 test.py:11(c)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
-- d --
100002 function calls in 0.075 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.065 0.065 0.075 0.075 <string>:3(<module>)
100000 0.010 0.000 0.010 0.000 test.py:15(d)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
-- a (again) --
300002 function calls in 60.890 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 30.487 30.487 60.890 60.890 <string>:3(<module>)
100000 0.049 0.000 0.049 0.000 test.py:5(<genexpr>)
100000 0.237 0.000 30.355 0.000 test.py:5(<lambda>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
100000 30.118 0.000 30.118 0.000 {range}
--a--
在61.764秒内调用300002个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1 30.881 30.881 61.764 61.764 :3()
100000 0.051 0.000 0.051 0.000测试。py:5()
100000 0.247 0.000 30.832 0.000测试。py:5()
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
100000 30.585 0.000 30.585 0.000{范围}
--b--
在0.076秒内调用100002个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1 0.066 0.066 0.076 0.076 :3()
100000 0.010 0.000 0.010 0.000试验。py:7(b)
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
--c--
在0.075秒内调用100002个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1 0.065 0.065 0.075 0.075 :3()
100000 0.010 0.000 0.010 0.000试验。py:11(c)
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
--d--
在0.075秒内调用100002个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1 0.065 0.065 0.075 0.075 :3()
100000 0.010 0.000 0.010 0.000试验。py:15(d)
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
--a(再次)--
60.890秒内调用300002个函数
订购人:标准名称
ncalls tottime percall cumtime percall文件名:lineno(函数)
1 30.487 30.487 60.890 60.890 :3()
100000 0.049 0.000 0.049 0.000测试。py:5()
100000 0.237 0.000 30.355 0.000试验。py:5()
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
100000 30.118 0.000 30.118 0.000{范围}
坐标轴是什么意思?我想你在几句话中都是倒转的?lambda版本是对数增长的版本。