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

227 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ObjectCache 技术文档
```markdown
# 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` 中记录其访问时间和大小。
#### 注意事项:
- 存在 bug`tmp[i][i]` 应为 `tmp[i][1]`(即 key原代码会导致索引错误。
- 正确写法应为:
```python
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` 中删除对应的元数据。
#### 异常处理:
- 删除失败时重新抛出异常。
---
## 使用示例
```python
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__` 方法中:
```python
for i in xrange(len(tmp)//2) :
del self[tmp[i][i]]
```
应改为:
```python
for _, key in tmp[:len(tmp)//2]:
del self[key]
```
或者修正索引错误:
```python
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()` 方法重写以同步清理 `_shadow` 和 `size`。
- 添加 `__contains__`、`keys()` 等方法的行为说明。
- 增加线程安全锁(多线程环境下使用时)。
---
## 依赖要求
- Python 2.7 或兼容版本(当前代码为 Python 2 风格)
- 必须导入模块:
```python
import time
```
否则运行时报错。
---
## 总结
`ObjectCache` 是一个轻量级的对象缓存工具,适合对内存敏感的应用场景。尽管存在一些实现缺陷,但其设计思路清晰,易于理解和扩展。建议在生产环境中结合更成熟的缓存库(如 `functools.lru_cache` 或第三方库 `cachetools`)使用,或在此基础上修复 bug 后封装成稳定组件。
```