-
Notifications
You must be signed in to change notification settings - Fork 0
/
memory_cache.py
126 lines (100 loc) · 3.74 KB
/
memory_cache.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# coding=utf-8
import time
from functools import wraps
from collections import OrderedDict
NEVER_EXPIRE = 0
class LRUCache(object):
def __init__(self, capacity):
self.capacity = capacity
self.cache = OrderedDict()
def put(self, key, value):
if key in self.cache:
del self.cache[key]
elif len(self.cache) >= self.capacity:
self.cache.popitem(last=False)
self.cache[key] = value
def get(self, key, default=None):
if key not in self.cache:
return default
value = self.cache.pop(key)
self.put(key, value)
return value
def __setitem__(self, key, value):
self.put(key, value)
def __getitem__(self, key):
return self.get(key)
def __contains__(self, key):
return key in self.cache
class FuncAttr(object):
def __init__(self, nExpireMs=NEVER_EXPIRE, bUniqueArg=True):
self.m_InstanceObj = None
self.m_nExpireMs = nExpireMs
self.m_bUniqueArg = bUniqueArg
self.dictArg2res = {}
def __get__(self, instance, cls):
self.m_InstanceObj = instance
return self
def _GetRes(self, key):
result, nCacheExpireTs = self.dictArg2res.get(key, (None, None))
return result, nCacheExpireTs
def _IsExpired(self, key=None, nCacheExpireTs=None):
if nCacheExpireTs is None:
_, nCacheExpireTs = self._GetRes(key)
if nCacheExpireTs is None:
return True
if self.m_nExpireMs == NEVER_EXPIRE:
return False
assert isinstance(nCacheExpireTs, (int, float))
return time.time() >= nCacheExpireTs
def MakeKey(self, args, kwargs):
if not self.m_bUniqueArg:
return "simple"
key = args
if kwargs:
for item in kwargs.iteritems():
key += item
return key
class MemoryCache(FuncAttr):
"""
函数缓存装饰器
"""
def __init__(self, nExpireMs=NEVER_EXPIRE, bUniqueArg=True, nSize=1024):
super(MemoryCache, self).__init__(nExpireMs, bUniqueArg)
self.dictArg2res = LRUCache(nSize)
def __call__(self, func):
@wraps(func)
def Wrapper(*args, **kwargs):
key = self.MakeKey(args, kwargs)
result, nCacheExpireTs = self._GetRes(key)
if not self._IsExpired(nCacheExpireTs=nCacheExpireTs):
return result
if self.m_InstanceObj is not None:
res = func(self.m_InstanceObj, *args, **kwargs)
else:
res = func(*args, **kwargs)
self.dictArg2res[key] = res, time.time() + self.m_nExpireMs / 1000.0
return res
return Wrapper
class DelayRun(FuncAttr):
"""
延迟调用装饰器
"""
def __init__(self, nDelayMs=1000, bUniqueArg=True, TickEngine=None):
assert nDelayMs > 0
super(DelayRun, self).__init__(nDelayMs, bUniqueArg)
self.m_TickEngine = TickEngine
def __call__(self, func):
@wraps(func)
def Wrapper(*args, **kwargs):
key = self.MakeKey(args, kwargs)
nTickID, nCacheExpireTs = self._GetRes(key)
if not self._IsExpired(key, nCacheExpireTs=nCacheExpireTs) and self.m_TickEngine.IsExistTickID(nTickID):
return nTickID
RegisterOnceTick = self.m_TickEngine.RegisterOnceTick
if self.m_InstanceObj is not None:
nTickID = RegisterOnceTick("", self.m_nExpireMs, func, self.m_InstanceObj, *args, **kwargs)
else:
nTickID = RegisterOnceTick("", self.m_nExpireMs, func, *args, **kwargs)
self.dictArg2res[key] = nTickID, time.time() + self.m_nExpireMs / 1000.0
return nTickID
return Wrapper