__slots__ 用法

810 阅读2分钟

看了一下 tech.oyster.com/save-ram-wi… 这篇文章,该作者发现通过使用__slots__ 可以让内存从25.5GB降到16.2GB,效果显著,节约了大量资源了。于是,我也通过例子实现了一遍,加深一下理解。

import sys

import resource  # 该库只能用于unix中


class NotUseSlots(object):
    def __init__(self):
        # 初始化属性
        self.test_string = 'This Type is  string'
        self.test_int = 300
        self.test_bool = False


class UseSlots(object):
    __slots__ = ['test_string', 'test_int', 'test_bool']

    def __init__(self):
        self.test_string = 'This Type is  string'
        self.test_int = 300
        self.test_bool = False


def test(cls):
    mem_init = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    lists = []

    for i in range(50000):
        lists.append(cls())

    mem_final = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    del lists
    print('Class: {0}:\n'.format(getattr(cls, '__name__')))
    print('Initial RAM usage:{:14,}'.format(mem_init))
    print('Final RAM usage: {:14,}'.format(mem_final))
    print('-'*20)


if __name__ == '__main__':
    test(globals()[sys.argv[1]])
    

我分别测试了这两个测试类NotUseSlots和UseSlots:

root@python:/data# python test_slots.py NotUseSlots
Class: NotUseSlots:

Initial RAM usage:         6,624
Final RAM usage:         15,468
--------------------
root@python:/data# python test_slots.py UseSlots
Class: UseSlots:

Initial RAM usage:         6,624
Final RAM usage:         10,092
--------------------
root@python:/data#

通过计算(15468-6624)/(10092-6624)发现未使用__slots__的内存消耗为使用__slots__的内存消耗使用2.25倍左右。(百万级是3.5倍左右) 所以可以根据实际需求相应的优化一下代码,节约服务器内存资源。

__slots__实现原理

__slots__中变量是类属性,类型为数据描述符(这篇文章写得不错 blog.csdn.net/lis_12/arti… 可以看看)。

虽然其变量是类属性但不同实例互不影响。因为描述符方法的一个参数为实例,建立一个实例和值的映射很轻松。

如果类定义了__slots__ ,该类的实例不会有__dict__属性。实例中__dict__属性是非常消耗内存的,当创建上百万级以上实例的时候,所有实例的__dict__会消耗大量内存。没有了__dict__的实例是无法动态添加属性的,而只能分配固定内存来缓存已知的__slots__里的属性。所以这也是使用了__slots__的类可以节约很多内存开销的原因吧。

因此对于不需要动态添加属性的类且实例在万级以上时,可以考虑使用__slots__来进行优化,万级以下效果不明显。