Bin*_*Bin 3 python performance interpreter list-comprehension
我正在研究Python中循环结构的性能问题,并发现以下语句:
除了列表推导的句法益处之外,它们通常比等效使用map更快或更快.(性能提示)
列表推导比等效的for循环运行得快一点(除非你只是扔掉结果).(Python速度)
我想知道引擎盖下有什么区别可以让列表理解这个优势.谢谢.
测试一:扔掉结果.
这是我们的虚拟功能:
def examplefunc(x):
pass
Run Code Online (Sandbox Code Playgroud)
以下是我们的挑战者:
def listcomp_throwaway():
[examplefunc(i) for i in range(100)]
def forloop_throwaway():
for i in range(100):
examplefunc(i)
Run Code Online (Sandbox Code Playgroud)
根据OP的问题,我不会对其原始速度进行分析,只是为什么.让我们来看看机器代码的差异.
--- List comprehension
+++ For loop
@@ -1,15 +1,16 @@
- 55 0 BUILD_LIST 0
+ 59 0 SETUP_LOOP 30 (to 33)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (100)
9 CALL_FUNCTION 1
12 GET_ITER
- >> 13 FOR_ITER 18 (to 34)
+ >> 13 FOR_ITER 16 (to 32)
16 STORE_FAST 0 (i)
- 19 LOAD_GLOBAL 1 (examplefunc)
+
+ 60 19 LOAD_GLOBAL 1 (examplefunc)
22 LOAD_FAST 0 (i)
25 CALL_FUNCTION 1
- 28 LIST_APPEND 2
- 31 JUMP_ABSOLUTE 13
- >> 34 POP_TOP
- 35 LOAD_CONST 0 (None)
- 38 RETURN_VALUE
+ 28 POP_TOP
+ 29 JUMP_ABSOLUTE 13
+ >> 32 POP_BLOCK
+ >> 33 LOAD_CONST 0 (None)
+ 36 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
比赛开始了.Listcomp的第一步是建立一个空列表,而for循环是建立一个循环.然后它们都继续加载全局范围(),常量100,并调用生成器的范围函数.然后他们都获得当前的迭代器并获得下一个项目,并将其存储到变量i中.然后他们加载examplefunc和i并调用examplefunc.Listcomp将它附加到列表并再次开始循环.For循环在三个指令中执行相同而不是两个.然后他们都加载None并返回它.
那么谁在这个分析中似乎更好?在这里,列表理解会执行一些冗余操作,例如构建列表并附加到它,如果您不关心结果.For循环也非常有效.
如果你计时,使用for循环比列表理解快三分之一.(在这个测试中,examplefunc将其参数除以5并将其抛弃而不是什么都不做.)
测试二:保持结果正常.
这个测试没有虚函数.所以这是我们的挑战者:
def listcomp_normal():
l = [i*5 for i in range(100)]
def forloop_normal():
l = []
for i in range(100):
l.append(i*5)
Run Code Online (Sandbox Code Playgroud)
差异对我们今天没用.它只是两个块中的两个机器码.
列出comp的机器代码:
55 0 BUILD_LIST 0
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (100)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 16 (to 32)
16 STORE_FAST 0 (i)
19 LOAD_FAST 0 (i)
22 LOAD_CONST 2 (5)
25 BINARY_MULTIPLY
26 LIST_APPEND 2
29 JUMP_ABSOLUTE 13
>> 32 STORE_FAST 1 (l)
35 LOAD_CONST 0 (None)
38 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
对于循环的机器代码:
59 0 BUILD_LIST 0
3 STORE_FAST 0 (l)
60 6 SETUP_LOOP 37 (to 46)
9 LOAD_GLOBAL 0 (range)
12 LOAD_CONST 1 (100)
15 CALL_FUNCTION 1
18 GET_ITER
>> 19 FOR_ITER 23 (to 45)
22 STORE_FAST 1 (i)
61 25 LOAD_FAST 0 (l)
28 LOAD_ATTR 1 (append)
31 LOAD_FAST 1 (i)
34 LOAD_CONST 2 (5)
37 BINARY_MULTIPLY
38 CALL_FUNCTION 1
41 POP_TOP
42 JUMP_ABSOLUTE 19
>> 45 POP_BLOCK
>> 46 LOAD_CONST 0 (None)
49 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
正如您可能已经知道的那样,列表理解的指令少于循环.
列表理解的清单:
range.100.range.i.i.l匿名空列表.对于循环的核对清单:
l匿名空列表.range.100.range.i.l.append在该列表上加载该属性.i.append.(不包括以下步骤:加载None,返回.)
列表理解不必执行以下操作:
i每个循环加载两次总而言之,如果要使用这些值,listcomp会快得多,但如果不这样做,则速度非常慢.
真正的速度
测试一:for循环更快约三分之一*
测试二:列表理解速度提高了大约三分之二*
*关于 - >小数点后第二位
| 归档时间: |
|
| 查看次数: |
815 次 |
| 最近记录: |