Python 是不是;否则";你有开销吗?
这两者之间是否存在性能差异:Python 是不是;否则";你有开销吗?,python,Python,这两者之间是否存在性能差异: for item in collection: if item == badItem: break else doFunction(item) 这是: for item in collection: if item == badItem: break doFunction(item) 假设我这样做了两亿次,那么任何性能差异都会有所帮助 编辑: 我并不是根据这个问题的结果来实现这个,我
for item in collection:
if item == badItem:
break
else
doFunction(item)
这是:
for item in collection:
if item == badItem:
break
doFunction(item)
假设我这样做了两亿次,那么任何性能差异都会有所帮助
编辑:
我并不是根据这个问题的结果来实现这个,我只是想知道理论上什么更快。我只是好奇。这听起来像是早熟的优化:不要这样做。 如果必须的话,在尝试优化程序之前,您应该让程序正常工作 如果你完成的应用程序比你需要的慢,那么测量,测量,测量。使用分析工具。速度慢的部分可能会让你感到惊讶。不要浪费时间修理速度不慢的部件
但是回到第一点:不要试图优化一个功能不完整的程序。正如Grant Birchmeier所说:测量,测量,测量 在linux上使用Python 3.3.1(默认值,2013年4月17日,22:30:32)[GCC 4.7.3]在我的对话框中我得到以下结果:
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.我只是比较整数,没有实际数据。我不知道你的
\uuuu eq\uuuu
有多贵,以及函数的功能等等。以下是两个版本的并排说明:
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
0设置循环40(至43)| 0设置循环40(至43)
3加载全局0(集合)| 3加载全局0(集合)
6获得ITER | 6获得ITER
国际热核实验堆第32号反应堆为7座(至42座)|国际热核实验堆第32号反应堆为7座(至42座)
10店快0(物品)| 10店快0(物品)
|
13加载快0(项目)| 13加载快0(项目)
16负载_全局1(坏项)| 16负载_全局1(坏项)
19比较运算2(=);19比较运算2(=)
22 POP_JUMP_IF_FALSE 29 22 POP_JUMP_IF_FALSE 29
|
25断开循环| 25断开循环
26跳|绝对7 | 26跳|向前0(到29)
|
29加载_全局2(doFunction)| 29加载_全局2(doFunction)
32加载快0(项目)| 32加载快0(项目)
35呼叫|功能1 | 35呼叫|功能1
38件流行上衣| 38件流行上衣
39跳|绝对7 | 39跳|绝对7
42 POP_块| 42 POP_块
43负载常数0(无)| 43负载常数0(无)
46返回值| 46返回值
如您所见,唯一的区别是JUMP\u ABSOLUTE
(带else
)与JUMP\u FORWARD
(不带它)。由于这两个操作码都紧跟在中断循环之后,因此它们在任何情况下都不会运行,因此这两个版本完全等效
这就是说,在中断语句(break/continue/return
)之后的else
通常被认为是一种代码味道(并且需要额外的无用行)
如果您对最大性能感兴趣,那么可能值得考虑.index
或itertools.takewhile
而不是If
的简单循环:如果您关心性能,首先运行代码,然后改进什么,最后改进那些东西
为了子孙后代,以下是我的计时结果。简单的回答是:即使经过数十亿次迭代,也没有真正的区别
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
语句的实际成本是多少,它显然比您正在执行的任何实际操作(例如您的\uuuuuueq\uuuuu
实现,或者您的实际doFunction
是什么,甚至只是您机器上发生的其他事情)都要低。检查timeit
模块,或者iPython
的魔力%timeit
自己来解决这个问题。试试计时你的vs[doFunction(item)for item in collection]
我认为第二个选项更好,因为它暗示你想做一个动作,除非有坏的项目。我非常怀疑额外的一个词会增加更多的执行时间……担心这些微小细节的性能差异,就像担心你每年露营时篝火的碳足迹一样。从技术上讲,它是非零的,我想有一些罕见的情况下,它是重要的,但总的来说,有一百万个更重要的贡献者在你的总碳足迹,即使你优化了所有这些,剩下的优化是很少值得的努力。你如何衡量(timeit
或其他东西),记录在案?另外,这些差异是可重复的还是仅仅是噪音?对于f in(testA,testB,testC):打印(f.\uu name,timeit.timeit(f,number=1))
这是一种糟糕的使用timeit
的方法。仅测量一次运行,可对各种噪声提供零保护。如果需要太长时间才能运行数千次,则将基准测试缩小(但仍具有代表性)。如果你不能使它变小,至少运行几次。@delnan可以随意这样做。“并且需要额外的无用线路”。。。以及一个额外的缩进水平!虽然在很多情况下都是这样,但在这个特定的案例中,没有什么需要衡量的——两个版本生成的操作码基本相同。@volcano——他直接询问了性能影响,这就是我关注的部分。我同意你的观点,无用的代码是无用的。@火山式风格与性能不同,而且