这之间是否有任何性能差异:
for item in collection:
if item == badItem:
break
else
doFunction(item)
而且:
for item in collection:
if item == badItem:
break
doFunction(item)
假设我这样做了几亿次,所以任何性能差异都会有所帮助。
编辑: 我实际上并没有根据这个问题的结果实现这个,我只是在理论上想知道什么是更快的。我只是好奇。
答案 0 :(得分:5)
以下是两个版本的并排:
0 SETUP_LOOP 40 (to 43) | 0 SETUP_LOOP 40 (to 43) 3 LOAD_GLOBAL 0 (collection) | 3 LOAD_GLOBAL 0 (collection) 6 GET_ITER | 6 GET_ITER 7 FOR_ITER 32 (to 42) | 7 FOR_ITER 32 (to 42) 10 STORE_FAST 0 (item) | 10 STORE_FAST 0 (item) | 13 LOAD_FAST 0 (item) | 13 LOAD_FAST 0 (item) 16 LOAD_GLOBAL 1 (badItem) | 16 LOAD_GLOBAL 1 (badItem) 19 COMPARE_OP 2 (==) | 19 COMPARE_OP 2 (==) 22 POP_JUMP_IF_FALSE 29 | 22 POP_JUMP_IF_FALSE 29 | 25 BREAK_LOOP | 25 BREAK_LOOP 26 JUMP_ABSOLUTE 7 | 26 JUMP_FORWARD 0 (to 29) | 29 LOAD_GLOBAL 2 (doFunction) | 29 LOAD_GLOBAL 2 (doFunction) 32 LOAD_FAST 0 (item) | 32 LOAD_FAST 0 (item) 35 CALL_FUNCTION 1 | 35 CALL_FUNCTION 1 38 POP_TOP | 38 POP_TOP 39 JUMP_ABSOLUTE 7 | 39 JUMP_ABSOLUTE 7 42 POP_BLOCK | 42 POP_BLOCK 43 LOAD_CONST 0 (None) | 43 LOAD_CONST 0 (None) 46 RETURN_VALUE | 46 RETURN_VALUE
正如您所看到的,唯一的区别是JUMP_ABSOLUTE
(else
}与JUMP_FORWARD
对比(没有它)。由于两个操作码都紧跟在BREAK_LOOP
之后,因此它们不会在任何情况下运行,因此两个版本完全等效。
也就是说,在破坏声明(else
)之后的break/continue/return
通常被认为是代码气味(并且需要额外的无用线)。
如果您对最高性能感兴趣,可能值得考虑使用.index
或itertools.takewhile
而不是使用if
的普通循环。
答案 1 :(得分:2)
这听起来像是预成熟的优化:不要这样做。
如果你不得不这样做,你应该在尝试优化程序之前使程序正常工作。
如果您的完成的应用程序比您需要的慢,那么测量,测量,测量。使用分析工具。缓慢的部分可能会让你感到惊讶。不要浪费时间固定那些速度不慢的部件。
但回到第一点:不要尝试优化功能不完整的程序。
答案 2 :(得分:1)
Grant Birchmeier说:衡量,衡量,衡量。
使用Python 3.3.1 (default, Apr 17 2013, 22:30:32) [GCC 4.7.3] on linux
在我的方框中,我得到了以下结果:
testA 0.7911653139999544
testB 0.7868194140028208
testC 0.7771379340010753
使用:
collection = [random.randint (1, 10000000) for _ in range (10000000) ]
badItem = 0
collection [5000000] = 0
def doFunction (item): pass
def testA ():
for item in collection:
if item == badItem: break
else: doFunction (item)
def testB ():
for item in collection:
if item == badItem: break
doFunction (item)
def testC ():
badIndex = collection.index (badItem)
for item in collection [:badIndex]:
doFunction (item)
YMMV。我只是在比较整数和没有真实世界的数据。我不知道你的__eq__
,doFunction
做了什么等等。
答案 3 :(得分:1)
Grant's answer说得对:如果你关心性能,首先要运行代码,然后measure需要改进什么,最后改进那些东西。
对于后代,这是我的时间结果。简短的回答:即使经过数十亿次迭代,也没有真正的区别。
With Else:
min: 0.001327058799944325
max: 0.0037289344766406884
mean: 0.002665085947631951
Without Else:
min: 0.0013189987034252226
max: 0.003550914613782652
mean: 0.002147321588495288
代码:
C:\>python
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> else_version = timeit.repeat('for i in c:\n\tif i == 0: break\n\telse:i += 1','import random;c=[random.randint(0,1) for _ in range(1000000)]', number = 10000, repeat=10)
>>> nelse_version = timeit.repeat('for i in c:\n\tif i == 0: break\n\ti += 1','import random;c=[random.randint(0,1) for _ in range(1000000)]', number = 10000, repeat=10)
>>> min(else_version)
0.001327058799944325
>>> max(else_version)
0.0037289344766406884
>>> sum(else_version)/10
0.002665085947631951
>>>
>>> min(nelse_version)
0.0013189987034252226
>>> max(nelse_version)
0.003550914613782652
>>> sum(nelse_version)/10
0.002147321588495288
>>>
无论实际使用else
声明的成本是多少,与您正在进行的任何实际操作(例如__eq__
实施或实际doFunction
实际操作相比,显然相形见绌)是,甚至只是你机器上发生的其他事情。)