Why is looping over range() in Python faster than using a while loop?
前几天我做了一些Python基准测试,我发现了一些有趣的东西。 下面是两个或多或少相同的循环。 循环1大约需要循环2执行的两倍。
循环1:
1 2 3 | int i = 0 while i < 100000000: i += 1 |
循环2:
1 2 | for n in range(0,100000000): pass |
为什么第一个循环这么慢? 我知道这是一个微不足道的例子,但它引起了我的兴趣。 range()函数有什么特别之处,它比以相同方式递增变量更有效吗?
看到python字节码的反汇编,你可能会得到一个更具体的想法
使用while循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 1 0 LOAD_CONST 0 (0) 3 STORE_NAME 0 (i) 2 6 SETUP_LOOP 28 (to 37) >> 9 LOAD_NAME 0 (i) # <- 12 LOAD_CONST 1 (100000000) # <- 15 COMPARE_OP 0 (<) # <- 18 JUMP_IF_FALSE 14 (to 35) # <- 21 POP_TOP # <- 3 22 LOAD_NAME 0 (i) # <- 25 LOAD_CONST 2 (1) # <- 28 INPLACE_ADD # <- 29 STORE_NAME 0 (i) # <- 32 JUMP_ABSOLUTE 9 # <- >> 35 POP_TOP 36 POP_BLOCK |
循环体有10个操作
使用范围:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 1 0 SETUP_LOOP 23 (to 26) 3 LOAD_NAME 0 (range) 6 LOAD_CONST 0 (0) 9 LOAD_CONST 1 (100000000) 12 CALL_FUNCTION 2 15 GET_ITER >> 16 FOR_ITER 6 (to 25) # <- 19 STORE_NAME 1 (n) # <- 2 22 JUMP_ABSOLUTE 16 # <- >> 25 POP_BLOCK >> 26 LOAD_CONST 2 (None) 29 RETURN_VALUE |
循环体有3个操作
运行C代码的时间比intepretor短得多,可以忽略。
使用
必须要说的是,while循环中存在大量的对象创建和破坏。
1 | i += 1 |
是相同的:
1 | i = i + 1 |
但是因为Python int是不可变的,所以它不会修改现有的对象;相反,它创造了一个具有新价值的全新物体。它基本上是:
1 | i = new int(i + 1) # Using C++ or Java-ish syntax |
垃圾收集器也将进行大量的清理工作。
"对象创建很昂贵"。
因为您在解释器中用C编写的代码中运行得更频繁。即i + = 1在Python中,如此慢(相对),而范围(0,...)是一个C调用,for循环也将主要在C中执行。
Python的大多数内置方法调用都是作为C代码运行的。必须解释的代码要慢得多。在内存效率和执行速度方面,差异是巨大的。 python内部结构已经过极端优化,最好利用这些优化。