我正在测试一些不同方法的速度来对我的一些数据进行复杂的迭代,我发现了一些奇怪的东西。似乎某个函数的局部大型列表会大大减慢该函数的速度,即使它没有触及该列表。例如,通过相同生成器函数的2个实例创建2个独立列表,第二次约慢2.5倍。如果在创建第二个列表之前删除了第一个列表,则两个迭代器都会使用相同的语言。
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。如果我在评论位置插入l1= []
或l1= len(l1)
,则for
个循环都需要4.5秒。
为什么函数中本地内存分配的速度与该函数变量的当前大小有关?
编辑: 禁用垃圾收集器会修复所有内容,因此必须由于它不断运行。结案!
答案 0 :(得分:9)
当你创建那么多新对象(300万个元组)时,垃圾收集器会陷入困境。如果你用gc.disable()关闭垃圾收集,那么问题就会消失(程序运行速度提高4倍)。
答案 1 :(得分:2)
没有更详细的仪器就不可能说出来。
作为非常非常初步的步骤,请检查主内存使用情况。如果您的RAM已满,并且您的操作系统正在分页到磁盘,那么您的性能将非常糟糕。在这种情况下,您可能最好将您的中间产品放在除内存之外的其他地方。如果您只需要顺序读取数据,请考虑写入普通文件;如果您的数据遵循严格的结构,请考虑持久保存到关系数据库中。
答案 2 :(得分:2)
我的猜测是,当第一个列表生成时,可用内存更多,这意味着列表在增长时需要重新分配的可能性更小。
在您使用第一个列表占用大量内存后,您的第二个列表会更高 因为python列表是动态调整大小所以需要重新分配的可能性。
答案 3 :(得分:0)
在函数返回之前,函数本地数据使用的内存不会被垃圾收集。除非您需要进行切片,否则使用大型数据集列表并不是一个好主意。
从您的示例来看,创建这些列表的目的并不完全清楚。您可能需要考虑使用生成器而不是列表,特别是如果列表将要迭代。如果需要对返回数据进行切片,那么将生成器转换为列表。