缓存与内存使用

1 投票
1 回答
612 浏览
提问于 2025-04-17 14:30

我有很多类,它们的功能都差不多:在创建的时候接收一个标识符(数据库里的主键),然后从数据库中加载数据。

我想把这些类的实例缓存起来,这样可以减少对数据库的访问次数。当缓存的大小达到一个临界值时,它应该删除那些最近最少被访问的缓存对象。

其实缓存的功能看起来是正常的,但我不知道怎么确定缓存的内存使用情况(在#下一行的结果和我预期的不一样这行之后)。

到目前为止我的代码是这样的:

#! /usr/bin/python3.2

from datetime import datetime
import random
import sys

class Cache:
    instance = None

    def __new__ (cls):
        if not cls.instance:
            cls.instance = super ().__new__ (cls)
            cls.instance.classes = {}
        return cls.instance

    def getObject (self, cls, ident):
        if cls not in self.classes: return None
        cls = self.classes [cls]
        if ident not in cls: return None
        return cls [ident]

    def cache (self, object):
        #Next line doesn't do what I expected
        print (sys.getsizeof (self.classes) )
        if object.__class__ not in self.classes:
            self.classes [object.__class__] = {}
        cls = self.classes [object.__class__]
        cls [object.ident] = (object, datetime.now () )


class Cached:
    def __init__ (self, cache):
        self.cache = cache

    def __call__ (self, cls):
        cls.cache = self.cache

        oNew = cls.__new__
        def new (cls, ident):
            cached = cls.cache ().getObject (cls, ident)
            if not cached: return oNew (cls, ident)
            cls.cache ().cache (cached [0] )
            return cached [0]
        cls.__new__ = new

        def init (self, ident):
            if hasattr (self, 'ident'): return
            self.ident = ident
            self.load ()
        cls.__init__ = init

        oLoad = cls.load
        def load (self):
            oLoad (self)
            self.cache ().cache (self)
        cls.load = load

        return cls


@Cached (Cache)
class Person:
    def load (self):
        print ('Expensive call to DB')
        print ('Loading Person {}'.format (self.ident) )
        #Just simulating
        self.name = random.choice ( ['Alice', 'Bob', 'Mallroy'] )

@Cached (Cache)
class Animal:
    def load (self):
        print ('Expensive call to DB')
        print ('Loading Animal {}'.format (self.ident) )
        #Just simulating
        self.species = random.choice ( ['Dog', 'Cat', 'Iguana'] )

sys.getsizeof返回的值让我觉得很奇怪。

我该怎么才能确定所有缓存对象的实际内存使用情况呢?

1 个回答

1

getsizeof 这个东西有点复杂,下面我给你举个例子:

getsizeof([])       # returns 72   ------------A
getsizeof([1,])     # returns 80   ------------B
getsizeof(1)        # returns 24   ------------C
getsizeof([[1,],])  # returns 80   ------------D
getsizeof([[1,],1]) # returns 88   ------------E

这里有一些值得注意的点:

  • A: 一个空列表的大小是72字节
  • B: 一个包含数字1的列表比空列表多8字节
  • C: 数字1本身并不是8字节。之所以会这样,是因为1作为一个独立的对象存在,所以C这一行返回的是这个对象的大小,而B返回的是空列表的大小加上对这个对象的引用。
  • D: 这就是一个空列表的大小加上对另一个列表的引用的大小
  • E: 一个空列表加上两个引用的大小是88字节

我想说的是,getsizeof 只能帮你获取某些东西的大小。你还需要知道这些东西所指向的其他东西的大小。这有点像递归的概念。

你可以看看这个链接,可能会对你有帮助: http://code.activestate.com/recipes/546530/

撰写回答