kevin-toolbox-dev 1.3.1__py3-none-any.whl → 1.3.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kevin_toolbox/__init__.py +2 -2
- kevin_toolbox/computer_science/algorithm/cache_manager/__init__.py +1 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/cache/__init__.py +2 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/cache/cache_base.py +89 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/cache/memo_cache.py +36 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/cache_manager.py +218 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/strategy/__init__.py +5 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/strategy/fifo_strategy.py +21 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/strategy/lfu_strategy.py +80 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/strategy/lru_strategy.py +43 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/strategy/lst_strategy.py +26 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/strategy/strategy_base.py +45 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/test/__init__.py +0 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/test/test_cache_builder.py +37 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/test/test_cache_manager.py +197 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/test/test_cache_strategy.py +129 -0
- kevin_toolbox/computer_science/algorithm/cache_manager/variable.py +28 -0
- kevin_toolbox/computer_science/algorithm/registration/registry.py +38 -16
- kevin_toolbox/data_flow/core/cache/__init__.py +1 -1
- kevin_toolbox/data_flow/core/cache/cache_manager_for_iterator.py +36 -168
- kevin_toolbox/data_flow/core/cache/test/__init__.py +0 -0
- kevin_toolbox/data_flow/core/cache/test/test_cache_manager_for_iterator.py +34 -0
- kevin_toolbox/data_flow/core/reader/file_iterative_reader.py +44 -9
- kevin_toolbox/data_flow/core/reader/unified_reader.py +2 -2
- kevin_toolbox/data_flow/core/reader/unified_reader_base.py +4 -5
- kevin_toolbox/data_flow/file/json_/converter/__init__.py +2 -2
- kevin_toolbox/data_flow/file/json_/converter/escape_tuple_and_set.py +23 -0
- kevin_toolbox/data_flow/file/json_/converter/{unescape_tuple.py → unescape_tuple_and_set.py} +7 -5
- kevin_toolbox/data_flow/file/json_/read_json.py +3 -3
- kevin_toolbox/data_flow/file/json_/write_json.py +3 -3
- kevin_toolbox/data_flow/file/kevin_notation/kevin_notation_reader.py +6 -5
- kevin_toolbox/data_flow/file/kevin_notation/read.py +4 -2
- kevin_toolbox/data_flow/file/kevin_notation/test/test_kevin_notation.py +15 -3
- kevin_toolbox/data_flow/file/markdown/generate_table.py +2 -2
- kevin_toolbox/math/utils/__init__.py +1 -1
- kevin_toolbox/math/utils/{spilt_integer_most_evenly.py → split_integer_most_evenly.py} +2 -2
- kevin_toolbox/nested_dict_list/get_nodes.py +9 -4
- kevin_toolbox/nested_dict_list/name_handler/build_name.py +1 -1
- kevin_toolbox/nested_dict_list/name_handler/parse_name.py +1 -1
- kevin_toolbox/nested_dict_list/set_default.py +44 -28
- kevin_toolbox/patches/for_matplotlib/__init__.py +1 -0
- kevin_toolbox/patches/for_matplotlib/generate_color_list.py +33 -0
- kevin_toolbox/patches/for_numpy/linalg/__init__.py +1 -0
- kevin_toolbox/patches/for_numpy/linalg/entropy.py +26 -0
- kevin_toolbox/patches/for_numpy/random/__init__.py +3 -0
- kevin_toolbox/patches/for_numpy/random/get_rng.py +64 -0
- kevin_toolbox/patches/for_numpy/random/truncated_multivariate_normal.py +129 -0
- kevin_toolbox/patches/for_numpy/random/truncated_normal.py +89 -0
- kevin_toolbox/patches/for_numpy/random/variable.py +10 -0
- kevin_toolbox/patches/for_optuna/serialize/for_study/dump.py +10 -2
- kevin_toolbox_dev-1.3.3.dist-info/METADATA +75 -0
- {kevin_toolbox_dev-1.3.1.dist-info → kevin_toolbox_dev-1.3.3.dist-info}/RECORD +54 -29
- kevin_toolbox/data_flow/file/json_/converter/escape_tuple.py +0 -20
- kevin_toolbox_dev-1.3.1.dist-info/METADATA +0 -91
- {kevin_toolbox_dev-1.3.1.dist-info → kevin_toolbox_dev-1.3.3.dist-info}/WHEEL +0 -0
- {kevin_toolbox_dev-1.3.1.dist-info → kevin_toolbox_dev-1.3.3.dist-info}/top_level.txt +0 -0
kevin_toolbox/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
__version__ = "1.3.
|
1
|
+
__version__ = "1.3.3"
|
2
2
|
|
3
3
|
|
4
4
|
import os
|
@@ -12,5 +12,5 @@ os.system(
|
|
12
12
|
os.system(
|
13
13
|
f'python {os.path.split(__file__)[0]}/env_info/check_validity_and_uninstall.py '
|
14
14
|
f'--package_name kevin-toolbox-dev '
|
15
|
-
f'--expiration_timestamp
|
15
|
+
f'--expiration_timestamp 1727520805 --verbose 0'
|
16
16
|
)
|
@@ -0,0 +1 @@
|
|
1
|
+
from .cache_manager import Cache_Manager
|
@@ -0,0 +1,89 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
|
4
|
+
class Cache_Base(ABC):
|
5
|
+
"""
|
6
|
+
缓存结构的基类
|
7
|
+
|
8
|
+
要求实现:
|
9
|
+
- 读取 _read_freely()
|
10
|
+
- 写入 _write_freely()
|
11
|
+
- 清除单个条目 _remove_freely()
|
12
|
+
- 判断是否命中 has()
|
13
|
+
- 获取缓存已占空间 len()
|
14
|
+
- 清空所有内容 clear()
|
15
|
+
等方法。
|
16
|
+
|
17
|
+
对外提供:
|
18
|
+
- 只读取已有条目 read()
|
19
|
+
- 只写入不存在条目 write()
|
20
|
+
- 只清除已存在的单个条目 remove()
|
21
|
+
- 判断是否命中 has()
|
22
|
+
- 获取缓存已占空间 len()
|
23
|
+
- 清空所有内容 clear()
|
24
|
+
等接口。
|
25
|
+
"""
|
26
|
+
|
27
|
+
def read(self, key):
|
28
|
+
"""只允许读取已存在的条目"""
|
29
|
+
if self.has(key=key):
|
30
|
+
return self._read_freely(key=key)
|
31
|
+
else:
|
32
|
+
raise KeyError(f"key {key} not found")
|
33
|
+
|
34
|
+
def write(self, key, value):
|
35
|
+
"""只允许写入不已存在的条目"""
|
36
|
+
if not self.has(key=key):
|
37
|
+
self._write_freely(key=key, value=value)
|
38
|
+
else:
|
39
|
+
raise KeyError(f"key {key} already exists")
|
40
|
+
|
41
|
+
def remove(self, key):
|
42
|
+
"""只允许删除已存在的条目"""
|
43
|
+
if self.has(key=key):
|
44
|
+
self._remove_freely(key=key)
|
45
|
+
else:
|
46
|
+
raise KeyError(f"key {key} not found")
|
47
|
+
|
48
|
+
@abstractmethod
|
49
|
+
def _read_freely(self, key):
|
50
|
+
return self.read(key=key)
|
51
|
+
|
52
|
+
@abstractmethod
|
53
|
+
def _write_freely(self, key, value):
|
54
|
+
pass
|
55
|
+
|
56
|
+
@abstractmethod
|
57
|
+
def _remove_freely(self, key):
|
58
|
+
pass
|
59
|
+
|
60
|
+
@abstractmethod
|
61
|
+
def has(self, key) -> bool:
|
62
|
+
pass
|
63
|
+
|
64
|
+
@abstractmethod
|
65
|
+
def len(self) -> int:
|
66
|
+
pass
|
67
|
+
|
68
|
+
@abstractmethod
|
69
|
+
def clear(self):
|
70
|
+
pass
|
71
|
+
|
72
|
+
def __getitem__(self, key):
|
73
|
+
# self[key]
|
74
|
+
return self.read(key=key)
|
75
|
+
|
76
|
+
def __setitem__(self, key, value):
|
77
|
+
# self[key] = value
|
78
|
+
self.write(key=key, value=value)
|
79
|
+
|
80
|
+
def __contains__(self, key):
|
81
|
+
# if key in self:
|
82
|
+
# return True
|
83
|
+
# else:
|
84
|
+
# return False
|
85
|
+
return self.has(key=key)
|
86
|
+
|
87
|
+
def __len__(self):
|
88
|
+
# len(self)
|
89
|
+
return self.len()
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.cache import Cache_Base
|
2
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.variable import CACHE_BUILDER_REGISTRY
|
3
|
+
|
4
|
+
|
5
|
+
@CACHE_BUILDER_REGISTRY.register()
|
6
|
+
class Memo_Cache(Cache_Base):
|
7
|
+
"""
|
8
|
+
基于内存的缓存结构
|
9
|
+
"""
|
10
|
+
name = ":in_memory:Memo_Cache"
|
11
|
+
|
12
|
+
def __init__(self, **kwargs):
|
13
|
+
self.cache_s = dict()
|
14
|
+
|
15
|
+
def _read_freely(self, key):
|
16
|
+
return self.cache_s[key]
|
17
|
+
|
18
|
+
def _write_freely(self, key, value):
|
19
|
+
self.cache_s[key] = value
|
20
|
+
|
21
|
+
def _remove_freely(self, key):
|
22
|
+
self.cache_s.pop(key)
|
23
|
+
|
24
|
+
def has(self, key):
|
25
|
+
return key in self.cache_s
|
26
|
+
|
27
|
+
def len(self):
|
28
|
+
return len(self.cache_s)
|
29
|
+
|
30
|
+
def clear(self):
|
31
|
+
self.cache_s.clear()
|
32
|
+
|
33
|
+
|
34
|
+
# 添加其他别名
|
35
|
+
for name in [":in_memory:Memo", ":in_memory:MC", ":in_memory:memory"]:
|
36
|
+
CACHE_BUILDER_REGISTRY.add(obj=Memo_Cache, name=name, b_force=False, b_execute_now=False)
|
@@ -0,0 +1,218 @@
|
|
1
|
+
import time
|
2
|
+
from .strategy import Strategy_Base
|
3
|
+
from .cache import Cache_Base
|
4
|
+
from .variable import CACHE_STRATEGY_REGISTRY, CACHE_BUILDER_REGISTRY
|
5
|
+
|
6
|
+
|
7
|
+
class Cache_Manager:
|
8
|
+
"""
|
9
|
+
缓存管理器
|
10
|
+
|
11
|
+
提供以下接口:
|
12
|
+
- 添加条目 add(key, value, b_allow_overwrite)
|
13
|
+
- 获取条目 get(key, b_add_if_not_found, default_factory, default)
|
14
|
+
- 删除并返回条目 pop(key)
|
15
|
+
- 判断是否有该条目 has()
|
16
|
+
- 清空所有内容 clear()
|
17
|
+
|
18
|
+
并支持以下用法:
|
19
|
+
通过 len(.) 获取缓存大小,通过 in 操作符判断是否有某个条目
|
20
|
+
|
21
|
+
|
22
|
+
相关变量:
|
23
|
+
self.cache: 缓存
|
24
|
+
self.metadata_s:缓存的属性数据
|
25
|
+
包含以下字段,各字段将自动更新
|
26
|
+
例如:{
|
27
|
+
<key>: {
|
28
|
+
"last_time": xxx, # 最近读取时间
|
29
|
+
"initial_time": xxx, # 最初读取时间
|
30
|
+
"survival_time": xxx, # survival_time:=last_time-initial_time
|
31
|
+
"counts": xxx, # 读取次数
|
32
|
+
},
|
33
|
+
...
|
34
|
+
}
|
35
|
+
self.strategy: 缓存更新策略
|
36
|
+
"""
|
37
|
+
|
38
|
+
def __init__(self, **kwargs):
|
39
|
+
"""
|
40
|
+
参数:
|
41
|
+
upper_bound: <int> 当缓存容量超过该值时,触发重整(抛弃部分条目以将容量降低到 refactor_size 指定的大小)
|
42
|
+
refactor_size: <int/float> 内存重整后的容量大小
|
43
|
+
当设置为 int 时,表示具体容量的大小;
|
44
|
+
当设置为 float 时表示占 upper_bound 的比例
|
45
|
+
默认为 0.5
|
46
|
+
strategy: <str/dict/Strategy_Base> 管理策略
|
47
|
+
cache: <str/dict/Cache_Base> 缓存种类
|
48
|
+
"""
|
49
|
+
# 默认参数
|
50
|
+
paras = {
|
51
|
+
"upper_bound": None,
|
52
|
+
"refactor_size": 0.5,
|
53
|
+
"strategy": ":by_last_time:LRU",
|
54
|
+
"cache": ":in_memory:Memo",
|
55
|
+
}
|
56
|
+
|
57
|
+
# 获取参数
|
58
|
+
paras.update(kwargs)
|
59
|
+
|
60
|
+
# 校验参数
|
61
|
+
assert isinstance(paras["upper_bound"], int) and paras["upper_bound"] > 0, \
|
62
|
+
"upper_bound must be a positive integer"
|
63
|
+
if isinstance(paras["refactor_size"], float):
|
64
|
+
paras["refactor_size"] = int(paras["refactor_size"] * paras["upper_bound"])
|
65
|
+
assert 0 <= paras["refactor_size"] <= paras["upper_bound"], \
|
66
|
+
"refactor_size must be less than upper_bound and bigger than zero"
|
67
|
+
# strategy
|
68
|
+
assert isinstance(paras["strategy"], (str, dict, Strategy_Base)), \
|
69
|
+
"strategy must be a string, dict of paras or a Strategy_Base object"
|
70
|
+
if isinstance(paras["strategy"], str):
|
71
|
+
strategy = CACHE_STRATEGY_REGISTRY.get(name=paras["strategy"])()
|
72
|
+
elif isinstance(paras["strategy"], dict):
|
73
|
+
strategy = CACHE_STRATEGY_REGISTRY.get(name=paras["strategy"]["name"])(
|
74
|
+
**paras["strategy"].get("paras", dict()))
|
75
|
+
else:
|
76
|
+
strategy = paras["strategy"]
|
77
|
+
# cache
|
78
|
+
assert isinstance(paras["cache"], (str, dict, Cache_Base)), \
|
79
|
+
"cache must be a string, dict of paras or a Cache_Base object"
|
80
|
+
if isinstance(paras["cache"], str):
|
81
|
+
cache = CACHE_BUILDER_REGISTRY.get(name=paras["cache"])()
|
82
|
+
elif isinstance(paras["cache"], dict):
|
83
|
+
cache = CACHE_BUILDER_REGISTRY.get(name=paras["cache"]["name"])(**paras["cache"].get("paras", dict()))
|
84
|
+
else:
|
85
|
+
cache = paras["cache"]
|
86
|
+
|
87
|
+
self.paras = paras
|
88
|
+
self.strategy = strategy # type:Strategy_Base
|
89
|
+
self.cache = cache # type:Cache_Base
|
90
|
+
self.metadata_s = dict() # 保存条目的相关信息
|
91
|
+
|
92
|
+
def add(self, key, value, b_allow_overwrite=True):
|
93
|
+
"""
|
94
|
+
以 key 为查询键,将 value 添加到缓存中
|
95
|
+
|
96
|
+
参数:
|
97
|
+
key:
|
98
|
+
value:
|
99
|
+
b_allow_overwrite: <boolean> 是否允许覆写缓存中已有的条目
|
100
|
+
默认为 True
|
101
|
+
"""
|
102
|
+
# 判断是否需要进行覆写
|
103
|
+
if self.cache.has(key=key):
|
104
|
+
if id(value) != id(self.cache.read(key=key)):
|
105
|
+
if b_allow_overwrite:
|
106
|
+
self.__remove_of_cache(key=key)
|
107
|
+
else:
|
108
|
+
raise KeyError(f'key: {key} already exists, modification of existing entries is prohibited')
|
109
|
+
else:
|
110
|
+
return
|
111
|
+
# 记录到缓存
|
112
|
+
self.__write_of_cache(key=key, value=value)
|
113
|
+
|
114
|
+
def __write_of_cache(self, key, value):
|
115
|
+
"""
|
116
|
+
向缓存中新增不存在的条目
|
117
|
+
"""
|
118
|
+
temp = time.time()
|
119
|
+
metadata = {
|
120
|
+
"initial_time": temp, # 最初读取时间(加入缓存的时间)
|
121
|
+
"last_time": temp, # 最近读取时间
|
122
|
+
"survival_time": 0.0, # 最后一次读取与加入缓存时间之差,last_time - initial_time
|
123
|
+
"counts": 0, # 读取次数
|
124
|
+
}
|
125
|
+
#
|
126
|
+
self.cache.write(key=key, value=value)
|
127
|
+
self.metadata_s[key] = metadata
|
128
|
+
# 通知策略管理器
|
129
|
+
self.strategy.notified_by_write_of_cache(key=key, value=value, metadata=metadata)
|
130
|
+
|
131
|
+
# 判断是否重构
|
132
|
+
if len(self.cache) <= self.paras["upper_bound"]:
|
133
|
+
return
|
134
|
+
# 从策略管理器获取建议
|
135
|
+
# 根据建议删除条目
|
136
|
+
suggest_keys = self.strategy.suggest(refactor_size=self.paras["refactor_size"])
|
137
|
+
assert len(suggest_keys) == len(self.cache) - self.paras["refactor_size"], \
|
138
|
+
f'expect {len(self.cache) - self.paras["refactor_size"]} deletion suggestions, but got {len(suggest_keys)}'
|
139
|
+
for key in suggest_keys:
|
140
|
+
self.__remove_of_cache(key=key)
|
141
|
+
|
142
|
+
def __remove_of_cache(self, key):
|
143
|
+
"""
|
144
|
+
从缓存中删除存在的条目
|
145
|
+
"""
|
146
|
+
self.cache.remove(key=key)
|
147
|
+
metadata = self.metadata_s.pop(key)
|
148
|
+
# 通知策略管理器
|
149
|
+
self.strategy.notified_by_remove_of_cache(key=key, metadata=metadata)
|
150
|
+
|
151
|
+
def get(self, key, b_add_if_not_found=False, default_factory=None, **kwargs):
|
152
|
+
"""
|
153
|
+
获取 key 对应的值
|
154
|
+
|
155
|
+
参数:
|
156
|
+
key: <hashable>
|
157
|
+
default: 默认值
|
158
|
+
当 key 在缓存中不存在时返回
|
159
|
+
default_factory: <callable> 用于产生默认值的函数
|
160
|
+
当 key 在缓存中不存在时返回该函数的结果
|
161
|
+
使用该参数相对于 default 能延迟默认值的产生(如果不需要用到默认值就不生成),提高效率
|
162
|
+
注意!!上面两个参数同时指定时,将以前者为准。
|
163
|
+
b_add_if_not_found: <boolean> 当 key 在缓存中不存在时,是否添加到缓存中
|
164
|
+
默认为 False
|
165
|
+
"""
|
166
|
+
if self.cache.has(key=key):
|
167
|
+
value = self.__read_of_cache(key=key)
|
168
|
+
elif "default" in kwargs or callable(default_factory):
|
169
|
+
value = kwargs["default"] if "default" in kwargs else default_factory()
|
170
|
+
if b_add_if_not_found:
|
171
|
+
self.__write_of_cache(key=key, value=value)
|
172
|
+
else:
|
173
|
+
raise KeyError(key)
|
174
|
+
return value
|
175
|
+
|
176
|
+
def pop(self, key):
|
177
|
+
"""
|
178
|
+
从缓存中删除 key 对应的条目,并返回该条目的值
|
179
|
+
"""
|
180
|
+
if self.cache.has(key=key):
|
181
|
+
value = self.__read_of_cache(key=key)
|
182
|
+
self.__remove_of_cache(key=key)
|
183
|
+
else:
|
184
|
+
raise KeyError(key)
|
185
|
+
return value
|
186
|
+
|
187
|
+
def __read_of_cache(self, key):
|
188
|
+
"""
|
189
|
+
读取缓存中 已经存在的 条目
|
190
|
+
"""
|
191
|
+
value = self.cache.read(key=key)
|
192
|
+
metadata = self.metadata_s[key]
|
193
|
+
# 更新 metadata
|
194
|
+
metadata["last_time"] = time.time()
|
195
|
+
metadata["survival_time"] = metadata["last_time"] - metadata["initial_time"]
|
196
|
+
metadata["counts"] += 1
|
197
|
+
# 通知策略管理器
|
198
|
+
self.strategy.notified_by_read_of_cache(key=key, value=value, metadata=metadata)
|
199
|
+
|
200
|
+
return value
|
201
|
+
|
202
|
+
def has(self, key):
|
203
|
+
"""
|
204
|
+
判断 key 是否在缓存中
|
205
|
+
注意!!不会更新 metadata
|
206
|
+
"""
|
207
|
+
return self.cache.has(key=key)
|
208
|
+
|
209
|
+
def clear(self):
|
210
|
+
self.cache.clear()
|
211
|
+
self.metadata_s.clear()
|
212
|
+
self.strategy.notified_by_clear_of_cache()
|
213
|
+
|
214
|
+
def __len__(self):
|
215
|
+
return len(self.cache)
|
216
|
+
|
217
|
+
def __contains__(self, key):
|
218
|
+
return self.has(key)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
from collections import OrderedDict
|
2
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.strategy import LRU_Strategy
|
3
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.variable import CACHE_STRATEGY_REGISTRY
|
4
|
+
|
5
|
+
|
6
|
+
@CACHE_STRATEGY_REGISTRY.register()
|
7
|
+
class FIFO_Strategy(LRU_Strategy):
|
8
|
+
"""
|
9
|
+
删除最后一次访问时间最久远的部分
|
10
|
+
drop items with smaller initial_time
|
11
|
+
"""
|
12
|
+
|
13
|
+
name = ":by_initial_time:FIFO_Strategy"
|
14
|
+
|
15
|
+
def notified_by_read_of_cache(self, key, value, metadata):
|
16
|
+
pass
|
17
|
+
|
18
|
+
|
19
|
+
# 添加其他别名
|
20
|
+
for name in [":by_initial_time:FIFO", ":by_initial_time:First_In_First_Out", ":by_initial_time:drop_smaller"]:
|
21
|
+
CACHE_STRATEGY_REGISTRY.add(obj=FIFO_Strategy, name=name, b_force=False, b_execute_now=False)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import heapq
|
2
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.strategy import Strategy_Base
|
3
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.variable import CACHE_STRATEGY_REGISTRY
|
4
|
+
|
5
|
+
|
6
|
+
class Score_to_Key:
|
7
|
+
def __init__(self, score, key):
|
8
|
+
self.score = score
|
9
|
+
self.key = key
|
10
|
+
|
11
|
+
def __lt__(self, other):
|
12
|
+
return self.score < other.score
|
13
|
+
|
14
|
+
def __eq__(self, other):
|
15
|
+
return self.score == other.score
|
16
|
+
|
17
|
+
def __gt__(self, other):
|
18
|
+
return self.score > other.score
|
19
|
+
|
20
|
+
def __repr__(self):
|
21
|
+
return f"Counts_to_Key(key:{self.key}, score:{self.score})"
|
22
|
+
|
23
|
+
|
24
|
+
@CACHE_STRATEGY_REGISTRY.register()
|
25
|
+
class LFU_Strategy(Strategy_Base):
|
26
|
+
"""
|
27
|
+
删除访问频率最低的部分
|
28
|
+
drop items with smaller counts
|
29
|
+
"""
|
30
|
+
|
31
|
+
name = ":by_counts:LFU_Strategy"
|
32
|
+
|
33
|
+
def __init__(self):
|
34
|
+
self.order_ls = list() # 最小堆
|
35
|
+
self.record_s = dict()
|
36
|
+
|
37
|
+
def notified_by_write_of_cache(self, key, value, metadata):
|
38
|
+
assert (metadata is None or metadata["counts"] == 0) and key not in self.record_s
|
39
|
+
self.record_s[key] = Score_to_Key(score=0, key=key)
|
40
|
+
heapq.heappush(self.order_ls, self.record_s[key])
|
41
|
+
|
42
|
+
def notified_by_read_of_cache(self, key, value, metadata):
|
43
|
+
assert metadata is None or metadata["counts"] == self.record_s[key].score + 1
|
44
|
+
self.record_s[key].score += 1
|
45
|
+
|
46
|
+
def notified_by_remove_of_cache(self, key, metadata):
|
47
|
+
temp = self.record_s.pop(key)
|
48
|
+
temp.score = -1
|
49
|
+
heapq.heapify(self.order_ls)
|
50
|
+
temp = heapq.heappop(self.order_ls)
|
51
|
+
assert temp.key == key
|
52
|
+
|
53
|
+
def notified_by_clear_of_cache(self):
|
54
|
+
self.record_s.clear()
|
55
|
+
self.order_ls.clear()
|
56
|
+
|
57
|
+
def suggest(self, refactor_size):
|
58
|
+
heapq.heapify(self.order_ls)
|
59
|
+
res = []
|
60
|
+
temp_ls = []
|
61
|
+
for _ in range(len(self.order_ls) - refactor_size):
|
62
|
+
temp = heapq.heappop(self.order_ls)
|
63
|
+
res.append(temp.key)
|
64
|
+
temp_ls.append(temp)
|
65
|
+
self.order_ls = temp_ls + self.order_ls
|
66
|
+
return res
|
67
|
+
|
68
|
+
def clear(self):
|
69
|
+
self.notified_by_clear_of_cache()
|
70
|
+
|
71
|
+
|
72
|
+
# 添加其他别名
|
73
|
+
for name in [":by_counts:LFU", ":by_counts:Least_Frequently_Used", ":by_counts:drop_smaller"]:
|
74
|
+
CACHE_STRATEGY_REGISTRY.add(obj=LFU_Strategy, name=name, b_force=False, b_execute_now=False)
|
75
|
+
|
76
|
+
if __name__ == "__main__":
|
77
|
+
max_heap = []
|
78
|
+
for i, j in [(-5, "a"), (-2, "adafd"), (-7, "ad"), (-1, "a"), (-10, "fasfde")]:
|
79
|
+
heapq.heappush(max_heap, Score_to_Key(i, j))
|
80
|
+
print(max_heap)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from collections import OrderedDict
|
2
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.strategy import Strategy_Base
|
3
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.variable import CACHE_STRATEGY_REGISTRY
|
4
|
+
|
5
|
+
|
6
|
+
@CACHE_STRATEGY_REGISTRY.register()
|
7
|
+
class LRU_Strategy(Strategy_Base):
|
8
|
+
"""
|
9
|
+
删除最后一次访问时间最久远的部分
|
10
|
+
drop items with smaller last_time
|
11
|
+
"""
|
12
|
+
|
13
|
+
name = ":by_last_time:LRU_Strategy"
|
14
|
+
|
15
|
+
def __init__(self):
|
16
|
+
self.record_s = OrderedDict()
|
17
|
+
|
18
|
+
def notified_by_write_of_cache(self, key, value, metadata):
|
19
|
+
self.record_s[key] = None
|
20
|
+
|
21
|
+
def notified_by_read_of_cache(self, key, value, metadata):
|
22
|
+
self.record_s.pop(key)
|
23
|
+
self.record_s[key] = None
|
24
|
+
|
25
|
+
def notified_by_remove_of_cache(self, key, metadata):
|
26
|
+
self.record_s.pop(key)
|
27
|
+
|
28
|
+
def notified_by_clear_of_cache(self):
|
29
|
+
self.record_s.clear()
|
30
|
+
|
31
|
+
def suggest(self, refactor_size):
|
32
|
+
if refactor_size == 0:
|
33
|
+
return list(self.record_s.keys())
|
34
|
+
else:
|
35
|
+
return list(self.record_s.keys())[:-refactor_size]
|
36
|
+
|
37
|
+
def clear(self):
|
38
|
+
self.record_s.clear()
|
39
|
+
|
40
|
+
|
41
|
+
# 添加其他别名
|
42
|
+
for name in [":by_last_time:LRU", ":by_last_time:Least_Recently_Used", ":by_last_time:drop_smaller"]:
|
43
|
+
CACHE_STRATEGY_REGISTRY.add(obj=LRU_Strategy, name=name, b_force=False, b_execute_now=False)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import heapq
|
2
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.strategy import Strategy_Base, LFU_Strategy
|
3
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.strategy.lfu_strategy import Score_to_Key
|
4
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.variable import CACHE_STRATEGY_REGISTRY
|
5
|
+
|
6
|
+
|
7
|
+
@CACHE_STRATEGY_REGISTRY.register()
|
8
|
+
class LST_Strategy(LFU_Strategy):
|
9
|
+
"""
|
10
|
+
删除访问频率最低的部分
|
11
|
+
drop items with smaller survival_time
|
12
|
+
"""
|
13
|
+
|
14
|
+
name = ":by_survival_time:LST_Strategy"
|
15
|
+
|
16
|
+
def notified_by_write_of_cache(self, key, value, metadata):
|
17
|
+
self.record_s[key] = Score_to_Key(score=metadata["survival_time"], key=key)
|
18
|
+
heapq.heappush(self.order_ls, self.record_s[key])
|
19
|
+
|
20
|
+
def notified_by_read_of_cache(self, key, value, metadata):
|
21
|
+
self.record_s[key].score = metadata["survival_time"]
|
22
|
+
|
23
|
+
|
24
|
+
# 添加其他别名
|
25
|
+
for name in [":by_survival_time:LST", ":by_survival_time:Least_Survival_Time", ":by_survival_time:drop_smaller"]:
|
26
|
+
CACHE_STRATEGY_REGISTRY.add(obj=LST_Strategy, name=name, b_force=False, b_execute_now=False)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
|
4
|
+
class Strategy_Base(ABC):
|
5
|
+
"""
|
6
|
+
缓存管理策略的基类
|
7
|
+
|
8
|
+
要求实现:
|
9
|
+
- notified_by_write_of_cache()
|
10
|
+
- notified_by_read_of_cache()
|
11
|
+
- notified_by_remove_of_cache()
|
12
|
+
- notified_by_clear_of_cache()
|
13
|
+
- 返回需要删除的条目的键的列表 suggest()
|
14
|
+
- 清空所有内容 clear()
|
15
|
+
等方法。
|
16
|
+
|
17
|
+
其中 notified_by_xxx_of_cache 系列方法用于接受在 Cache_Manager 中的通讯,比如 notified_by_write_of_cache 方法
|
18
|
+
将在 Cache_Manager 中每次调用 cache 的 write 方法时被调用。利用这些通讯接口,使得策略管理器可以提前追踪、感知条目的变化,
|
19
|
+
从而进行一些预处理操作,以免在后续需要其提出重构建议时,才当场进行过大的计算量。
|
20
|
+
"""
|
21
|
+
|
22
|
+
@abstractmethod
|
23
|
+
def notified_by_write_of_cache(self, key, value, metadata):
|
24
|
+
pass
|
25
|
+
|
26
|
+
@abstractmethod
|
27
|
+
def notified_by_read_of_cache(self, key, value, metadata):
|
28
|
+
pass
|
29
|
+
|
30
|
+
@abstractmethod
|
31
|
+
def notified_by_remove_of_cache(self, key, metadata):
|
32
|
+
pass
|
33
|
+
|
34
|
+
@abstractmethod
|
35
|
+
def notified_by_clear_of_cache(self):
|
36
|
+
self.clear()
|
37
|
+
|
38
|
+
@abstractmethod
|
39
|
+
def suggest(self, refactor_size) -> list:
|
40
|
+
"""返回需要删除的条目的键的列表"""
|
41
|
+
pass
|
42
|
+
|
43
|
+
@abstractmethod
|
44
|
+
def clear(self):
|
45
|
+
pass
|
File without changes
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import pytest
|
2
|
+
from kevin_toolbox.patches.for_test import check_consistency
|
3
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.cache import Cache_Base
|
4
|
+
from kevin_toolbox.computer_science.algorithm.cache_manager.variable import CACHE_BUILDER_REGISTRY
|
5
|
+
|
6
|
+
|
7
|
+
def test_memo_cache():
|
8
|
+
print("test Memo_Cache")
|
9
|
+
|
10
|
+
cache = CACHE_BUILDER_REGISTRY.get(name=":in_memory:Memo")() # type: Cache_Base
|
11
|
+
|
12
|
+
# 读写
|
13
|
+
cache.write(key="1", value=1)
|
14
|
+
cache[2] = "2"
|
15
|
+
check_consistency(cache["1"], 1)
|
16
|
+
check_consistency(cache.read(2), "2")
|
17
|
+
# 禁止重复写入
|
18
|
+
with pytest.raises(KeyError):
|
19
|
+
cache.write(key="1", value=2)
|
20
|
+
# 禁止读取/删除不存在条目
|
21
|
+
with pytest.raises(KeyError):
|
22
|
+
cache.read(key=1)
|
23
|
+
with pytest.raises(KeyError):
|
24
|
+
cache.remove(key=1)
|
25
|
+
|
26
|
+
# 容量判断
|
27
|
+
check_consistency(len(cache), 2)
|
28
|
+
|
29
|
+
# 删除与命中判断
|
30
|
+
check_consistency(cache.has("1"), True)
|
31
|
+
check_consistency(cache.has(2), True)
|
32
|
+
cache.remove(2)
|
33
|
+
check_consistency(cache.has(2), False)
|
34
|
+
|
35
|
+
# 清空
|
36
|
+
cache.clear()
|
37
|
+
check_consistency(len(cache), 0)
|