【问题标题】:python: while True vs while (condition) efficiencypython:while True vs while(条件)效率
【发布时间】:2019-11-04 05:23:38
【问题描述】:

我最近开始学习编程(使用 Python)。我有两段代码使用 while 循环:

a=100000000
#piece of code 1    
while a > 0:
    a-=10
print("done")

#piece of code 2
while True:
    a-=10
    if a <= 0:
       print("done")
       break

两者在功能上是等效的,即它们本质上执行相同的任务。出于好奇,我使用 time 模块记录了使用此 while 循环的两个版本执行此操作所需的时间。结果是:

代码 1:0.99 秒
代码 2:0.89 秒

它们表现出基本相同的性能,尽管代码 2 的效率稍高一些。这没关系,因为即使对于非常大的数字,这种差异基本上也无关紧要。然而,这对我来说有点出乎意料,因为我相信第一个 while 循环执行的操作更少。有人能解释一下为什么第二段代码效率更高吗?

【问题讨论】:

  • 第二个循环模拟了一个 do-while 循环,减少了一次检查。现在差异可能是别的东西(你必须检查字节码才能真正理解发生了什么),但有必要了解两者之间的逻辑差异,并且它们并不总是等价的。
  • 更少的语句并不意味着更少的操作。第一个仍然需要评估&gt; 的次数与第二个评估&lt;= 的次数相同。除非测量不确定性是解释,否则我可以想象&gt; 是根据&lt;= 实现的。
  • 我在 Python 3.6 上的 IPython 5.5 中得到了 0.882s 和 0.900s。我尝试更改 a 的值并得到类似的结果。但无论如何,如果结果始终处于同一数量级,这里就没有什么真正有趣的事情发生了。

标签: python python-3.x while-loop


【解决方案1】:

我把这些 sn-ps 放在两个函数中:

def first():
    a=100000000
    while a > 0:
        a-=10

def second():
    a=100000000
    while True:
        a-=10
        if a <= 0:
            break

然后使用timeit.timeit,实际上是second,它一直被认为需要更长的时间(尽管差异真的可以忽略不计)。

from timeit import timeit

timeit(first, number=100)
timeit(second, number=100)

然后我通过基本上从dis docs 复制示例来检查字节码。这表明两个 sn-ps 的字节码几乎相同,唯一的区别在于操作码的排序方式,second 包含一条附加指令,即BREAK_LOOP

import dis
from collections import Counter

first_bytecode = dis.Bytecode(first)
for instr in first_bytecode:
    print(instr.opname)

second_bytecode = dis.Bytecode(second)
for instr in second_bytecode:
    print(instr.opname)

# easier to compare with Counters
first_b = Counter(x.opname for x in first_bytecode)
sec_b = Counter(x.opname for x in second_bytecode)

最后,人们可能会认为顺序可能会产生影响(它可以),但为了进行公平比较,second 应该首先检查中断条件,然后再从a 中减去。然后考虑第三个函数:

def third():
    a=100000000
    while True:
        if a <= 0:
            break
        a-=10

比较third 的字节码,您会发现它的顺序实际上与first 的字节码相同,唯一的区别是单个BREAK_LOOP 卡在中间某处。

如果我希望这能向您展示一个操作码的执行对于代码的整体性能而言通常是多么微不足道的话。我认为 Donald Knuth 的 the immortal words 特别适合这个场合:

我们应该忘记小的效率,比如大约 97% 的时间:过早优化是万恶之源。

【讨论】:

  • 感谢详细的回复和代码,以更深入地检查我的代码的执行情况。这些说明将来肯定对我有用。
  • 3% 的时间这些东西是必要的。
猜你喜欢
  • 2015-02-15
  • 2015-07-09
  • 1970-01-01
  • 2019-02-12
  • 2016-05-16
  • 2021-11-07
  • 2021-04-09
  • 2013-03-02
  • 2011-03-22
相关资源
最近更新 更多