Python pandas在垃圾收集中花费了过多的时间

问题描述 投票:1回答:2

我正在研究一个复杂的python代码,它在垃圾收集中花费了大约40%的执行时间。

 ncalls    tottime  percall  cumtime  percall filename:lineno(function)

 **6028  494.097    0.082  494.097    0.082** {built-in method gc.collect}

 1900  205.709    0.108  205.709    0.108 {built-in method time.sleep}

  778   26.858    0.035  383.476    0.493 func1.py:51(fill_trades)

有没有办法减少对gc.collect的调用次数?我尝试了gc.disable(),但它的有效性受到限制,因为Cpython主要使用引用计数。我正在使用python 3.6。

python pandas garbage-collection performance-testing
2个回答
1
投票

如果没有看到代码,这是不可能正确回答的。但是,您可以使用一些通用提示来改善这种情况。

主要是:限制分配数量。你是否经常在微小的包装中重新包装一些没用的东西?你是否经常复制部分字符串?你在做很多复制数据的消息解析吗?找出最常分配内存并改进的内容。 https://pypi.python.org/pypi/memory_profiler在这里可能会有所帮助。

针对具体情况的修复:

  • 你在做很多数学密集型操作吗?也许移动到像numpy这样的东西会有所帮助,因为你可以使用真实的,可变的,类型化的数组而不是列表。
  • 你有很多数据处理代码吗?您可以在其上注释类型并使用cython编译模块,以消除将值包装到python对象中的需要。
  • 对于原始内存(解析/文件处理/ ...),您可以使用memoryviews保存一些分配:https://eli.thegreenplace.net/2011/11/28/less-copies-in-python-with-the-buffer-protocol-and-memoryviews

最后 - 你确定收集时间有问题吗?从跟踪中,您可以看到列表中的第二个位置是time.sleep。如果你的gc.collect占运行时间的40%,那么time.sleep需要16% - 为什么不在那时触发收集呢?无论如何,你明确地在睡觉。

编辑:此外,我相信你在某处明确地调用gc.collect。该调用不会自动出现在pstats输出中。要找出位置,请尝试:

your_pstats_object.print_callers('gc.collect')

1
投票

我遇到了类似的问题,我的代码花了90%的时间用于垃圾收集。我的功能在测试中每个呼叫花了大约90毫秒,但在生产中每个呼叫接近1秒。我跟踪它到熊猫检查它的SettingWithCopyWarning安静的形式。

在我的例子中,我创建了一个像df = pd.DataFrame(data)[fieldlist]的数据帧切片,然后分配了一个新的列df['foo'] = ...。此时df._is_copy显示我们对原始数据帧有一个弱参数,所以当我们调用__setitem__时,它会测试_check_setitem_copy然后执行完整的垃圾收集循环以杀死weakref gc.collect(2)

在生产中,我的代码试图每秒调用该函数几次,在缓存中有一堆大对象(dicts),因此垃圾收集周期非常昂贵。通过确保我首先没有创建副本来修复,性能提高了近15倍: - |

© www.soinside.com 2019 - 2024. All rights reserved.