python的性能';s控制流语句
我正在阅读Python维基,上面写着 在2.0版的Python中也添加了列表理解。它们提供了一种在语法上更紧凑、更高效的方式来编写上述for循环: 然而,我发现当我测试这个时,我得到了一些意想不到的结果python的性能';s控制流语句,python,loops,for-loop,while-loop,Python,Loops,For Loop,While Loop,我正在阅读Python维基,上面写着 在2.0版的Python中也添加了列表理解。它们提供了一种在语法上更紧凑、更高效的方式来编写上述for循环: 然而,我发现当我测试这个时,我得到了一些意想不到的结果 In [22]: def while_loop(n): ...: i = 0 ...: while i < n: ...: i+=1 ...: In [23]: def while_loop_2(n): ...:
In [22]: def while_loop(n):
...: i = 0
...: while i < n:
...: i+=1
...:
In [23]: def while_loop_2(n):
...: while n > 0:
...: n-=1
...:
In [24]: def for_loop(n):
...: for _ in range(n):
...: pass
...:
In [30]: %timeit(for_loop(1000000))
10 loops, best of 3: 23.9 ms per loop
In [31]: %timeit(while_loop(1000000))
10 loops, best of 3: 37.1 ms per loop
In [32]: %timeit(while_loop_2(1000000))
10 loops, best of 3: 38 ms per loop
In [33]: %timeit([1 for _ in range(1000000)])
10 loops, best of 3: 43.2 ms per loop
[22]中的:定义while_循环(n):
…:i=0
…:当我0时:
…:n-=1
...:
[24]中:_循环的定义(n):
…:对于范围内的u(n):
…:通过
...:
在[30]:%timeit(对于_循环(1000000))
10个环路,最佳3个:每个环路23.9毫秒
在[31]:%timeit(while_loop(1000000))
10个回路,最佳3个:每个回路37.1毫秒
在[32]:%timeit(while_loop_2(1000000))
10个回路,最好为3:38 ms/回路
在[33]:%timeit([1代表范围内(1000000)])
10个回路,最佳3个:每个回路43.2毫秒
这就引出了一些问题:
for
循环比列表理解快得多?(速度几乎是原来的两倍)while_loop_2
比while_loop
慢?为什么计数器递增与递减的差异会产生速度上的差异?我的天真让我相信代码行数越少=速度越快-显然不是这样while\u loop\u 2
实际上比while\u loop
更快。新问题是:
while
循环有什么不同作为序言,您应该知道您的“比较”应该单独分析(而不是相互比较),因为
for
循环,因此,我开始回答问题1#1,因为
for
循环迭代。列表理解会迭代,并在内存中创建一个列表。当然,这会增加所需的总时间。单凭这一点就足以说服您,但如果不是这样,请查看已反汇编的字节码,看看每个字节码都在做什么。您可以使用dis
模块执行此操作。我实际上用dis来回答你的第三个问题
#2,至于这个,我无法在python3.6上复制
%%timeit
i = 0; n = 100000
while i < n: i += 1
11.5 ms ± 65.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
通常,基于减量的循环应该快一点,因为与0(n>0
)的比较通常比与非零值(i
)的比较快。但是三角洲通常是“认真的,不要担心”有点小
要回答第三个问题,我们需要挖掘一下。让我们看看字节码
import dis
蟒蛇3.6
蟒蛇2.7
dis.dis(
''n=100000
当n>0:n-=1''时
)
0向前跳15648(到15651)
3片+2片
4.
5.
6.
7.
8.
9
10一元正
11继续循环26984
14导入-单元名称8293(8293)
17片+2片
18向前跳15904(至15925)
21片+2
22
23就地分水岭
24片+2
25向前跳11552(到11580)
28删除子项CR
29片+2
30
请注意,生成的字节码之间存在巨大差异。区别就在这里。您忘了在链接中测试上面的
循环:
newlist = []
for word in oldlist:
newlist.append(word.upper())
带列表附加的迭代:
In [104]: %%timeit
...: alist = []
...: for i in range(10000):
...: alist.append(i)
...:
1.07 ms ± 10.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
等价表理解
In [105]: timeit [i for i in range(10000)]
491 µs ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这确实比list-append循环快
从范围对象创建相同的列表:
In [106]: timeit list(range(10000))
265 µs ± 679 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
不执行任何操作迭代:
In [107]: %%timeit
...: for i in range(10000):
...: pass
...:
273 µs ± 9.15 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
其他一些列表创建:
In [109]: timeit list(map(lambda i:i, range(10000)))
1.41 ms ± 3.12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [110]: timeit list(i for i in range(10000))
784 µs ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
#1的原因是,您的列表理解还创建了一个新的列表(这会带来成本),因此它与普通for循环的比较并不是判断列表理解性能的有效方法。相反,您应该将列表理解与创建列表的其他模式进行比较您的for_loop():pass
与执行增广赋值的两个while循环不公平比较。将列表comp与范围内i的进行比较…:alist.append(i)
循环。列表comp返回某种类型的列表,而不仅仅是迭代或计数。但对于类似的任务,速度差异是适度的。@aydow对于#3,我只能推测,因为我不是一个核心开发人员,但2和3之间的许多变化主要与性能有关。。。就我所知,while可能是其中之一。@aydow我认为最大的区别在于字节码是如何生成的。使用dis
,您可以查看。
In [106]: timeit list(range(10000))
265 µs ± 679 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [107]: %%timeit
...: for i in range(10000):
...: pass
...:
273 µs ± 9.15 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [109]: timeit list(map(lambda i:i, range(10000)))
1.41 ms ± 3.12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [110]: timeit list(i for i in range(10000))
784 µs ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)