繁体   English   中英

Python function 因存在大列表而变慢

[英]Python function slows down with presence of large list

我正在测试几种不同方法对我的一些数据进行复杂迭代的速度,我发现了一些奇怪的东西。 似乎在某些 function 本地有一个大列表会大大减慢 function 的速度,即使它没有触及该列表。 例如,通过同一个生成器 function 的 2 个实例创建 2 个独立列表,第二次的速度大约慢 2.5 倍。 如果在创建第二个列表之前删除了第一个列表,则两个迭代器 go 的速度相同。

def f():  
    l1, l2 = [], []  
    for c1, c2 in generatorFxn():  
        l1.append((c1, c2))  
    # destroying l1 here fixes the problem 
    for c3, c4 in generatorFxn():  
        l2.append((c3, c4))

这些列表最终每个大约有 310 万个项目,但我也看到了较小列表的相同效果。 第一个for循环运行大约需要 4.5 秒,第二个需要 10.5 秒。 如果我在评论 position 中插入l1= []l1= len(l1) ,则两个for循环都需要 4.5 秒。

为什么 function 中本地 memory 分配的速度与该函数变量的当前大小有关?

编辑:禁用垃圾收集器可以修复所有问题,因此必须是由于它不断运行。 结案!

当您创建那么多新对象(300 万个元组)时,垃圾收集器就会陷入困境。 如果您使用 gc.disable() 关闭垃圾收集,问题就会消失(并且程序运行速度快 4 倍以启动)。

没有更详细的仪器是不可能的。

作为一个非常非常初步的步骤,检查您的主要 memory 使用情况。 如果您的 RAM 已全部填满并且您的操作系统正在分页到磁盘,那么您的性能将非常糟糕。 在这种情况下,您最好将中间产品放在 memory 以外的其他地方。 如果您只需要顺序读取数据,请考虑写入普通文件; 如果您的数据遵循严格的结构,请考虑持久化到关系数据库中。

我的猜测是,当创建第一个列表时,有更多的 memory 可用,这意味着随着列表的增长,需要重新分配的机会更少。

在您使用第一个列表占用相当大的 memory 块后,您的第二个列表随着 python 列表的大小是动态大小的而增长,因此需要重新分配的可能性更高。

在 function 返回之前,function 本地数据使用的 memory 不会被垃圾收集。 除非您需要进行切片,否则对大型 collections 数据使用列表并不是一个好主意。

从您的示例来看,创建这些列表的目的并不完全清楚。 您可能需要考虑使用生成器而不是列表,尤其是在列表将被迭代的情况下。 如果您需要对返回数据进行切片,请在那时将生成器转换为列表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM