Python:为什么比for-in块更快地弹出队列?

Wil*_*ill 9 python optimization for-loop while-loop

我一直在研究python脚本来分析CSV.其中一些文件相当大(1-2百万条记录),脚本需要数小时才能完成.

我改变了记录从for-in循环处理到while循环的方式,并且加速非常显着.演示如下:

>>> def for_list():
...     for d in data:
...             bunk = d**d
... 
>>> def while_list():
...     while data:
...             d = data.pop(0)
...             bunk = d**d
... 
>>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> import timeit
>>> timeit.timeit(for_list)
1.0698931217193604
>>> timeit.timeit(while_list)
0.14515399932861328
Run Code Online (Sandbox Code Playgroud)

几乎快一个数量级.我从来没有看过python字节码,但我可能会说,但事实证明它while_list有更多的指令.

那么这里发生了什么?这里有原则我可以申请其他课程吗?是否有for比这快十倍的情况while

编辑:正如@HappyLeapSecond指出的那样,我并不完全清楚内部发生了什么timeit .差异消失了以下:

>>> def for_list():
...     data = [x for x in range(1000)]
...     for d in data:
...             bunk = d**d
... 
>>> def while_list():
...     data = [x for x in range(1000)]
...     while data:
...             d = data.pop(0)
...             bunk = d**d
>>> timeit.timeit(while_list, number=1000)
12.006330966949463
>>> timeit.timeit(for_list, number=1000)
11.847280025482178
Run Code Online (Sandbox Code Playgroud)

这让我的"真实"剧本如此简单地加速变得非常奇怪.我最好的猜测是迭代方法需要更多交换?我有一个40G交换分区,脚本填充大约15-20G.弹出会减少交换吗?

unu*_*tbu 12

while_list正在改变全球data.timeit.timeit不重置的值data.默认情况下,每次timeit.timeit调用for_listwhile_list一百万次.在第一次调用之后,执行0循环后返回的while_list后续调用while_list因为data已经为空.

您需要data在每次调用之前重置值for_listwhile_list执行公平的基准测试.


import timeit

def for_list(data):
    for d in data:
        bunk = d ** d


def while_list(data):
    while data:
        d = data.pop(0)
        bunk = d ** d

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

print(timeit.timeit('data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for_list(data)', 'from __main__ import for_list'))
# 0.959696054459

print(timeit.timeit('data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; while_list(data)', 'from __main__ import while_list'))
# 2.40107011795
Run Code Online (Sandbox Code Playgroud)

pop(0)是一个O(n)操作.与复杂度相比,在长度循环内执行该操作nwhile_list产生总体时间复杂度.正如预期的那样,速度越快,优势越大,长度越大.O(n**2)O(n)for_listfor_listndata

  • @sebastian:`timeit.timeit`默认重复调用`while_list`一百万次.在第一次调用`while_list`之后,`data`为空.所以对于999,999次运行,`while_loop`太快完成了. (3认同)