【发布时间】:2015-10-11 11:24:36
【问题描述】:
我一直试图理解为什么在某些情况下 Python 3 与 Python 2 相比实际上要花费更多时间,以下是我从 python 3.4 到 python 2.7 验证的几个案例。
注意:我已经解决了一些问题,例如Why is there no xrange function in Python3? 和loop in python3 much slower than python2 和Same code slower in Python3 as compared to Python2,但我觉得我没有得到这个问题背后的真正原因。
我已经尝试了这段代码来展示它是如何产生影响的:
MAX_NUM = 3*10**7
# This is to make compatible with py3.4.
try:
xrange
except:
xrange = range
def foo():
i = MAX_NUM
while i> 0:
i -= 1
def foo_for():
for i in xrange(MAX_NUM):
pass
当我尝试使用 py3.4 和 py2.7 运行这个程序时,我得到了以下信息 结果。
注意:这些统计数据来自带有2.6Ghz 处理器的64 bit 机器,并在单循环中使用time.time() 计算时间。
Output : Python 3.4
-----------------
2.6392083168029785
0.9724123477935791
Output: Python 2.7
------------------
1.5131521225
0.475143909454
我真的不认为 while 或 xrange 从 2.7 到 3.4 发生了变化,我知道 range 已经开始在 py3.4 中充当 xrange 但正如文档所述
range()现在的行为类似于xrange()过去的行为,除了它适用于任意大小的值。后者不再存在。
这意味着从xrange 更改为range 与更改名称非常相似,但可以使用任意值。
我也验证了反汇编的字节码。
下面是函数foo()的反汇编字节码:
Python 3.4:
---------------
13 0 LOAD_GLOBAL 0 (MAX_NUM)
3 STORE_FAST 0 (i)
14 6 SETUP_LOOP 26 (to 35)
>> 9 LOAD_FAST 0 (i)
12 LOAD_CONST 1 (0)
15 COMPARE_OP 4 (>)
18 POP_JUMP_IF_FALSE 34
15 21 LOAD_FAST 0 (i)
24 LOAD_CONST 2 (1)
27 INPLACE_SUBTRACT
28 STORE_FAST 0 (i)
31 JUMP_ABSOLUTE 9
>> 34 POP_BLOCK
>> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
python 2.7
-------------
13 0 LOAD_GLOBAL 0 (MAX_NUM)
3 STORE_FAST 0 (i)
14 6 SETUP_LOOP 26 (to 35)
>> 9 LOAD_FAST 0 (i)
12 LOAD_CONST 1 (0)
15 COMPARE_OP 4 (>)
18 POP_JUMP_IF_FALSE 34
15 21 LOAD_FAST 0 (i)
24 LOAD_CONST 2 (1)
27 INPLACE_SUBTRACT
28 STORE_FAST 0 (i)
31 JUMP_ABSOLUTE 9
>> 34 POP_BLOCK
>> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
下面是函数foo_for()的反汇编字节码:
Python: 3.4
19 0 SETUP_LOOP 20 (to 23)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_GLOBAL 1 (MAX_NUM)
9 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
12 GET_ITER
>> 13 FOR_ITER 6 (to 22)
16 STORE_FAST 0 (i)
20 19 JUMP_ABSOLUTE 13
>> 22 POP_BLOCK
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Python: 2.7
-------------
19 0 SETUP_LOOP 20 (to 23)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_GLOBAL 1 (MAX_NUM)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 6 (to 22)
16 STORE_FAST 0 (i)
20 19 JUMP_ABSOLUTE 13
>> 22 POP_BLOCK
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
如果我们比较两个字节码,它们会产生相同的反汇编字节码。
现在我想知道从 2.7 到 3.4 的哪些变化真正导致了给定代码中执行时间的巨大变化。
【问题讨论】:
-
贴出完整代码和测量方法
-
用整个解释器设置运行一次不会告诉你任何事情。改用
timeit.timeit()运行时间试验。
标签: python performance python-2.7 python-3.x cpython