apppublic/aidocs/ObjectCache.md
2025-10-05 11:23:33 +08:00

5.7 KiB
Raw Blame History

ObjectCache 技术文档

# ObjectCache 类技术文档

## 概述

`ObjectCache` 是一个基于字典的内存对象缓存类,用于管理具有大小属性的对象集合。它继承自 Python 内置的 `dict` 类,并扩展了容量限制、自动淘汰和访问时间追踪功能。

该缓存适用于需要控制内存使用量、并能通过 `.get_size()` 方法获取对象大小的场景。当缓存总大小接近预设上限时会触发基于最近最少使用LRU策略的半数淘汰机制。

---

## 特性

- 支持类似字典的键值存储操作。
- 自动跟踪每个对象的大小(需实现 `get_size()` 方法)。
- 设置最大缓存容量(以字节或其他单位计),防止内存溢出。
- 使用 LRU最近最少使用策略进行对象淘汰。
- 记录对象最后访问时间以支持淘汰逻辑。

---

## 类定义

```python
class ObjectCache(dict)

继承自 dict,因此支持所有标准字典操作(如 in, len(), 迭代等)。


初始化方法

__init__(self, maxsize=10000000, *args)

参数说明:

参数 类型 说明
maxsize int 缓存允许的最大总大小,默认为 10,000,000 单位(例如字节)。
*args tuple 传递给父类 dict 的初始化参数(可选)。

属性初始化:

属性 类型 说明
self.maxsize int 最大缓存容量限制。
self.size int 当前缓存中所有对象的总大小,初始为 0。
self._shadow dict 私有字典,记录每个键对应的 [最后访问时间, 对象大小]

⚠️ 注意:必须导入 time 模块,否则在设置项时会抛出 NameError


核心方法

__setitem__(key, item)

将对象插入或更新到缓存中。

行为流程:

  1. 调用 item.get_size() 获取对象大小。
  2. 若失败(无此方法或异常),则直接返回,不缓存该对象。
  3. 成功获取大小后,将其加到 self.size
  4. 如果当前总大小超过 maxsize
    • self._shadow 中提取所有 (访问时间, key) 元组。
    • 按访问时间排序(越早访问的排在前面)。
    • 删除前一半最久未访问的条目及其对应的数据。
  5. 调用父类 __setitem__ 存储新对象。
  6. _shadow 中记录其访问时间和大小。

注意事项:

  • 存在 bugtmp[i][i] 应为 tmp[i][1](即 key原代码会导致索引错误。
  • 正确写法应为:
    for i in xrange(len(tmp)//2):
        del self[tmp[i][1]]  # tmp[i] 是 (time, key),所以取 [1]
    

__getitem__(key)

获取指定键对应的对象。

行为流程:

  1. 尝试调用父类 __getitem__ 获取对象。
  2. 若存在,则更新该键在 _shadow 中的访问时间为当前时间(time.time())。
  3. 返回对象。

异常处理:

  • 若键不存在,重新抛出 KeyError

get(key, default=None)

安全获取指定键的对象,若不存在返回默认值。

参数:

参数 类型 说明
key any 要查找的键。
default any 键不存在时返回的默认值,默认为 None

实现逻辑:

  • 调用 self.has_key(key) 判断是否存在。
  • 存在则返回 self[key](触发 __getitem__ 并更新时间戳)。
  • 否则返回 default

推荐使用方式:比直接捕获异常更安全。


__delitem__(key)

删除指定键的对象。

行为流程:

  1. 调用父类 __delitem__ 删除主缓存中的对象。
  2. 若成功,从 self.size 中减去该对象的大小。
  3. self._shadow 中删除对应的元数据。

异常处理:

  • 删除失败时重新抛出异常。

使用示例

import time

class MyData:
    def __init__(self, data):
        self.data = data

    def get_size(self):
        return len(self.data)

# 创建缓存实例,最大容量为 1MB
cache = ObjectCache(maxsize=1024*1024)

# 添加对象
obj = MyData("Hello World" * 100)
cache['key1'] = obj

# 获取对象
data = cache.get('key1')
print(data)

# 删除对象
del cache['key1']

已知问题与改进建议

Bug 修复建议

__setitem__ 方法中:

for i in xrange(len(tmp)//2) :
    del self[tmp[i][i]]

应改为:

for _, key in tmp[:len(tmp)//2]:
    del self[key]

或者修正索引错误:

for i in range(len(tmp)//2):
    del self[tmp[i][1]]  # 取出 key

此外Python 2 风格的 xrange.iteritems() 建议升级为 Python 3 兼容语法。


⚙️ 性能优化建议

  • 当前淘汰策略每次都要排序全部元素,复杂度为 O(n log n),效率较低。
  • 可替换为优先队列或双向链表实现真正的 LRU 缓存,提升性能。
  • _shadow 结构可以考虑合并进主字典,减少维护成本。

💡 扩展功能建议

  • 提供 clear() 方法重写以同步清理 _shadowsize
  • 添加 __contains__keys() 等方法的行为说明。
  • 增加线程安全锁(多线程环境下使用时)。

依赖要求

  • Python 2.7 或兼容版本(当前代码为 Python 2 风格)
  • 必须导入模块:
    import time
    
    否则运行时报错。

总结

ObjectCache 是一个轻量级的对象缓存工具,适合对内存敏感的应用场景。尽管存在一些实现缺陷,但其设计思路清晰,易于理解和扩展。建议在生产环境中结合更成熟的缓存库(如 functools.lru_cache 或第三方库 cachetools)使用,或在此基础上修复 bug 后封装成稳定组件。