class CacheModule: def __init__(self, max_size: int, ttl_millis: int, from_remote): ''' :param max_size: max_size of the cache,using LRU :param ttl_millis: max live time for the objects :param from_remote: function to load data if the key not exists ''' self.cache = LRU(max_size=max_size) self.ttl = ttl_millis self.from_remote = from_remote self._lock = RLock() def multi_get(self, keys) -> dict: result, missing = {}, [] now = int(round(time.time() * 1000)) for key in keys: value: dict = self.cache.get(key) # key未命中 if not value: missing.append(key) # key超时 elif now < value['max_time']: missing.append(key) # key存在且不是默认值 elif value['data']: result[key] = value['data'] if len(missing) > 0: loads_d: dict = self.from_remote(missing) dft = { 'max_time': int(round(time.time() * 1000)) + self.ttl, 'data': {} } for key in missing: loads_d.setdefault(key, dft) self.multi_set(loads_d) return result def multi_set(self, data: dict): with self._lock: for k, v in data.items(): self.cache.setdefault(k, v) def remove(self, keys): with self._lock: for key in keys: self.cache.pop(key)
def test_lru_basic(): lru = LRU(max_size=1) repr(lru) # sanity lru['hi'] = 0 lru['bye'] = 1 assert len(lru) == 1 lru['bye'] assert lru.get('hi') is None del lru['bye'] assert 'bye' not in lru assert len(lru) == 0 assert not lru try: lru.pop('bye') except KeyError: pass else: assert False default = object() assert lru.pop('bye', default) is default try: lru.popitem() except KeyError: pass else: assert False lru['another'] = 1 assert lru.popitem() == ('another', 1) lru['yet_another'] = 2 assert lru.pop('yet_another') == 2 lru['yet_another'] = 3 assert lru.pop('yet_another', default) == 3 lru['yet_another'] = 4 lru.clear() assert not lru lru['yet_another'] = 5 second_lru = LRU(max_size=1) assert lru.copy() == lru second_lru['yet_another'] = 5 assert second_lru == lru assert lru == second_lru lru.update(LRU(max_size=2, values=[('a', 1), ('b', 2)])) assert len(lru) == 1 assert 'yet_another' not in lru lru.setdefault('x', 2) assert dict(lru) == {'x': 2} lru.setdefault('x', 3) assert dict(lru) == {'x': 2} assert lru != second_lru assert second_lru != lru
def test_lru_basic(): lru = LRU(max_size=1) repr(lru) # sanity lru['hi'] = 0 lru['bye'] = 1 assert len(lru) == 1 lru['bye'] assert lru.get('hi') is None del lru['bye'] assert 'bye' not in lru assert len(lru) == 0 assert not lru try: lru.pop('bye') except KeyError: pass else: assert False default = object() assert lru.pop('bye', default) is default try: lru.popitem() except KeyError: pass else: assert False lru['another'] = 1 assert lru.popitem() == ('another', 1) lru['yet_another'] = 2 assert lru.pop('yet_another') == 2 lru['yet_another'] = 3 assert lru.pop('yet_another', default) == 3 lru['yet_another'] = 4 lru.clear() assert not lru lru['yet_another'] = 5 second_lru = LRU(max_size=1) assert lru.copy() == lru second_lru['yet_another'] = 5 assert second_lru == lru assert lru == second_lru lru.update(LRU(max_size=2, values=[('a', 1), ('b', 2)])) assert len(lru) == 1 assert 'yet_another' not in lru lru.setdefault('x', 2) assert dict(lru) == {'x': 2} lru.setdefault('x', 3) assert dict(lru) == {'x': 2} assert lru != second_lru assert second_lru != lru