Python 3:在许多小物体上节省RAM内存

时间:2018-12-01 14:57:54

标签: python python-3.x object memory struct

我正在开发一个在运行时创建数万个小型Python对象的应用程序。不幸的是,Python对象因占用大量RAM而臭名昭著。我发现了这篇有关如何解决该问题的有趣文章:

http://www.qtrac.eu/pysavemem.html

本文提供了一些有用的技巧,但并未完全解释它们。我不能为某些建议的解决方案而烦恼。请帮助我获得见识。我们将一一介绍。


1。没有优化

本文的基线示例是简单的Rect类:

class Rect:

    def __init__(self, x1, y1, x2, y2):
        self.x1 = x1
        self.x2 = x2
        self.y1 = y1
        self.y2 = y2

在运行64位Python 3的64位计算机上,此对象将消耗400KB。


2。 __slots__技术

__slots__技术是迄今为止最简单的优化。这是文章中的示例:

class Rect:
    __slots__ = ("x1", "x2", "y1", "y2")

    def __init__(self, x1, y1, x2, y2):
        self.x1 = x1
        self.x2 = x2
        self.y1 = y1
        self.y2 = y2

必须事先声明对象的属性x1x2y1y2。您不能向此类创建的对象添加任意额外的数据。
这些实例仅消耗212KB RAM。内存大小几乎减少了50%。


3。 “单一Python对象”技术

到目前为止,Rect()实例将分别生成四个内部对象:x1x2y1y2。随后的新技术尝试做不同的事情。代替了四个对象,只创建了一个单个 Python对象:

class Rect:
    __slots__ = ("_data",)

    # We are not limited to using the same types; could mix any
    # fixed-width types we want. And, of course, we can add extra
    # items to the struct later if need be.
    Coords = struct.Struct("llll")

    def __init__(self, x1, y1, x2, y2):
        self._data = Rect.Coords.pack(x1, y1, x2, y2)

    @property
    def x1(self):
        return Rect.Coords.unpack(self._data)[0]

    @property
    def x2(self):
        return Rect.Coords.unpack(self._data)[1]

    @property
    def y1(self):
        return Rect.Coords.unpack(self._data)[2]

    @property
    def y2(self):
        return Rect.Coords.unpack(self._data)[3]

该文章指出,消耗的内存现在只有137KB。但是,它没有解释如何。我不能把头缠在某些表情上:

  • __slots__ = ("_data",)的实际作用是什么?

  • Coords是类成员,而不是实例成员。那么,如何通过这种方式为每个实例获取不同的数据?

  • 这些pack()unpack()方法实际上是做什么的?

  • "llll"的{​​{1}}的参数是否表示Struct()x1x2y1的输入y2

  • 该文章说该示例也可以扩展为具有可写属性。看起来如何?


4。 “单一Python对象”技术(缩短的代码)

最后,本文提供了类似的解决方案,但代码较短:

long

这个解决方案对我来说还不清楚...


您为解释这些优化技术所做的努力将不胜感激!如果适用,请随时提出其他解决方案。就个人而言,我使用最新的Python 3.7版本。

1 个答案:

答案 0 :(得分:0)

recordclass库的基础上还有另一种方法:

from recordclass import dataobject

class Rectangle(dataobject):
    x1:int
    x2:int
    y1:int
    y2:int

此解决方案所需的内存少于基于__slots__的解决方案。差异等于PyGC_Head的大小(在64位平台上为24字节)。与基于__slots__的解决方案相比,它可能还具有更快的实例创建路径:

class Rectangle(dataobject):
    x1:int
    x2:int
    y1:int
    y2:int
    __options__ = {'argsonly':True}