gpt4 book ai didi

python - python的控制流语句的性能

转载 作者:太空宇宙 更新时间:2023-11-03 13:08:21 27 4
gpt4 key购买 nike

我正在阅读有关 loops 的 Python wiki它说

List comprehensions were added to Python in version 2.0 as well. They provide a syntactically more compact and more efficient way of writing the above for loop:

但是,我发现当我对此进行测试时,我得到了一些意想不到的结果。

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

这引出了一些问题:

  1. 为什么 for 循环比列表理解快得多? (看起来快了近一倍)

  2. 为什么 while_loop_2while_loop 慢?为什么递增与递减计数器的差异会产生速度差异?我的天真让我相信更少的代码行 = 更快 - 显然事实并非如此

编辑:这是在 Python 2.7 中完成的。在 3.6 中,while_loop_2 实际上比 while_loop 更快。所以新问题:

  1. Python 2.7 和 3.x 之间的 while 循环有什么区别?

最佳答案

作为序言,您应该意识到您的“比较”应该被孤立地分析(而不是相互比较),因为

  1. for 循环是一个固定的迭代器,在其内部什么都不做
  2. while 循环在其主体中执行递减/递增,并且
  3. 列表理解不仅仅是一个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)

%%timeit
n = 100000
while n > 0: n -= 1

10.8 ms ± 380 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

一般来说,基于递减的循环应该快一点,因为与 0 的比较 (n > 0) 通常比与非零值的比较 (i < n) 更快。但是 delta 通常“说真的,别担心”有点小。


要回答#3,我们需要深入挖掘一下。让我们看看字节码。

import dis

python3.6

dis.dis(
'''n = 100000
while n > 0: n -= 1'''
)

1 0 LOAD_CONST 0 (100000)
2 STORE_NAME 0 (n)

2 4 SETUP_LOOP 20 (to 26)
>> 6 LOAD_NAME 0 (n)
8 LOAD_CONST 1 (0)
10 COMPARE_OP 4 (>)
12 POP_JUMP_IF_FALSE 24
14 LOAD_NAME 0 (n)
16 LOAD_CONST 2 (1)
18 INPLACE_SUBTRACT
20 STORE_NAME 0 (n)
22 JUMP_ABSOLUTE 6
>> 24 POP_BLOCK
>> 26 LOAD_CONST 3 (None)
28 RETURN_VALUE

python2.7

dis.dis(
'''n = 100000
while n > 0: n -= 1'''
)
0 JUMP_FORWARD 15648 (to 15651)
3 SLICE+2
4 <49>
5 <48>
6 <48>
7 <48>
8 <48>
9 <48>
10 UNARY_POSITIVE
11 CONTINUE_LOOP 26984
14 IMPORT_NAME 8293 (8293)
17 SLICE+2
18 JUMP_FORWARD 15904 (to 15925)
21 SLICE+2
22 <48>
23 INPLACE_DIVIDE
24 SLICE+2
25 JUMP_FORWARD 11552 (to 11580)
28 DELETE_SUBSCR
29 SLICE+2
30 <49>

请注意,生成的字节码存在巨大差异。区别就在这里。

关于python - python的控制流语句的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50752304/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com