对象过多:减少Python实例的内存开销

2020-07-17 00:42:08

每次在Python中创建类的实例时,都会消耗一些内存-包括实际上可能比您关心的数据更大的开销。创建一百万个对象,开销是原来的一百万倍。

而且这种开销可能会累积起来,要么会阻止您运行程序,要么会增加您在硬件配置上的花费。

那么让我们来看看这个开销到底有多大(预告:它很大!)。以及你能做些什么。

在Python中,普通类的每个实例在幕后将其属性存储在字典中。

任何Python对象的正常开销,可以是实例、整数或您拥有的任何对象,再加上空字典的开销。

从随机导入随机类Point:def__init__(self,x):self。x=x对象=[]for_in范围(1000000):r=随机()点=点(R)对象。附加(点)。

我们可以看到这三个类别的内存使用情况,外加第四个附加类别:

基本上,内存使用量至少是我们关心的实际信息(第3项,随机浮点数)的10倍。

如果您想给任何给定的对象添加任意属性,那么为每个对象都有一个字典是有意义的。大多数情况下,我们不想这样做:我们知道某个类将具有特定的属性集,仅此而已。

输入__SLOTS__。通过在类上设置此属性,并使用字符串列表指示属性列表:

就我们的目的而言,更重要的是,Python不会为每个对象创建字典。

从随机导入随机类Point:__Slot__=[";x";]#<;--允许的属性def__init__(self,x):self。x=x对象=[]for_in范围(1000000):r=随机()点=点(R)对象。附加(点)。

字典的开销现在没有了,内存使用量减少了60%,从207MB减少到86MB。对于一行代码来说,这不是什么坏事!

解决这个问题的另一种方法是注意,存储一百万个相同对象的列表是相当浪费的,特别是当操作将发生在对象组上时。因此,与其为每个点创建一个对象,为什么不只是为每个属性创建一个列表呢?

从随机导入随机点={";x";:[],#";y";:[],#";z";:[]#等}for_in范围(1000000):R=随机()点[";x";]。追加(%r)。

在这一点上,大部分开销是由于每个浮点数拥有一个Python对象的开销。

因此,通过使用Pandas DataFrame存储信息,您可以进一步减少内存使用量,达到约8MB:它将使用NumPy数组在内部高效地存储数字。

通常,一次存储过多的Python对象会浪费内存。一如既往,解决方案可能涉及压缩、批处理或索引:

我在本文中介绍的解决方案侧重于压缩:以更少的开销存储相同的信息。

如果不需要一次将所有数据存储在内存中,则可以成批处理数据,例如通过生成器返回数据。

最后,通过使用索引,您可以尝试只加载您实际关心的数据。

了解更多减少内存使用的技术-阅读Python的小型大数据指南的其余部分。

缺乏编程技能阻碍了构建数据科学模型?通过我的培训课程提高您的数据科学团队的软件工程技能,从而提高他们的工作效率。

你不是一名软件工程师,但你仍然要处理从错误到缓慢代码再到神秘错误的一切事情。编写可维护、快速且易于理解的软件将使您成为更好的数据科学家(更不用说更具就业能力)。

订阅我的时事通讯,每周都会有新的文章向您展示如何提高您的软件工程技能,从测试到打包再到性能: