2013-02-02 122 views
1

我有很多类都做同样的事情:他们在构建过程中收到一个标识符(DB中的PK),然后从DB加载。 我想缓存这些类的实例,以最大限度地减少对数据库的调用。当缓存达到临界尺寸时,应放弃最近访问过的缓存对象。缓存和内存使用

缓存实际上似乎工作正常,但不知何故我无法确定缓存的内存使用情况(在#Next line doesn't do what I expected之后的行中)。

我迄今为止代码:

#! /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

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 

这里的一些东西,值得注意的是:

  • 一个:空列表的大小为72
  • B:包含1的列表的大小更多是8个字节
  • C1的大小不是8个字节。造成这种奇怪的原因是1作为唯一实体与列表分开存在,因此C行返回实体的大小,而B返回空列表的大小加上对该实体的引用。
  • d:这是这样一个空列表的大小加上一个参考,以不同的列表
  • è:空单加两所引用= 88个字节

我试图在这里得到的是getsizeof只能帮助你获得大小的东西。你需要知道事物的大小以及事物引用的大小。这听起来像递归。

看看这个食谱,它可能会帮助你:http://code.activestate.com/recipes/546530/