需求場景
數據緩存或者持久化一般分爲磁盤緩存和內存緩存,如果從讀寫速度上我們當然希望數據讀取的書讀越快越好,所以內存緩存倍受青睞,但是內存緩存由於成本限制,我們不能把全部的數據放在內存緩存裏,我們該如何取捨呢?
LRU
LRU是Least Recently Used的縮寫,意思是最近最少使用的數據,也就是最近使用的數據在未來的一段時間內任然被使用,已經使用很久的數據在未來的一段時間內任然不會變使用。基於這個理念我們可以在內存中保留常用的數據!
就是我們定義一個指定容量的list,每次新加的數據我們都會放在list的最上面,每次訪問的數據也會被放在list的最上面,要是加入的數據超出最大容量,刪除list的最好一個!
算法源碼
1.OC源碼
a.實現
/// 初始化
/// @param capacity 容量大小
- (instancetype)initWithCapacity:(NSUInteger)capacity{
if(self == [super init]){
_capacity = capacity;
}
return self;
}
/// 將對象存入緩存,如果 anyValue 爲 nil,會刪除對象
/// @param anyValue value
/// @param key key
- (void)setValue:(id)anyValue forKey:(NSString *)key{
if(anyValue == nil){
// 刪除對象
return;
}
if([self.cacheDict.allKeys containsObject:key]){
// 當前值已經存在
[self.keys removeObject:key];
}else{
// 新存入的值
if(self.keys.count == _capacity){
// 超出最大值了 刪除棧裏第一個
NSString *firstKey = [self.keys firstObject];
[self.keys removeObject:firstKey];
[self.cacheDict removeObjectForKey:firstKey];
}
}
[self.cacheDict setValue:anyValue forKey:key];
[self.keys addObject:key];
}
/// 取對象
/// @param key key
- (id)valueForKey:(NSString *)key{
// 判斷是否存在
if([self.cacheDict.allKeys containsObject:key]){
[self.keys removeObject:key];
[self.keys addObject:key];
return [self.cacheDict objectForKey:key];
}else{
return nil;
}
}
/// 刪除對象
/// @param key key
- (void)removeObjectForKey:(NSString *)key{
if([self.cacheDict.allKeys containsObject:key]){
[self.keys removeObject:key];
[self.cacheDict removeObjectForKey:key];
}else{
/// 不存在
}
}
/// 獲取所有的數據
/// @param block 鍵值對回調
- (void)enumerateKeysAndValuesUsingBlock:(void (^)(NSString *key, id obj, BOOL *stop))block{
[self.keys enumerateObjectsUsingBlock:^(NSString * _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) {
if(block){
block(key, [self.cacheDict objectForKey:key], stop);
}
}];
}
/// 更新容量大小
/// @param capacity 容量大小
- (void)resetCapacity:(NSInteger)capacity{
_capacity = capacity;
}
- (NSMutableArray *)keys{
if(_keys == nil){
_keys = [[NSMutableArray alloc] init];
}
return _keys;
}
- (NSMutableDictionary *)cacheDict{
if(_cacheDict == nil){
_cacheDict = [[NSMutableDictionary alloc] init];
}
return _cacheDict;
}
b.使用示例
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
for (int i = 1; i<=5; i++) {
NSString *key = [NSString stringWithFormat:@"%d",i];
NSString *value = [NSString stringWithFormat:@"%d",i * 100];
[self.lruCacheMap setValue:value forKey:key];
}
[self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
NSLog(@"key, value == %@, %@",key, obj);
}];
NSLog(@"------------");
[self.lruCacheMap setValue:@"600" forKey:@"6"];
[self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
NSLog(@"key, value == %@, %@",key, obj);
}];
NSLog(@"------------");
NSLog(@"%@", [self.lruCacheMap valueForKey:@"5"]);
[self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
NSLog(@"key, value == %@, %@",key, obj);
}];
NSLog(@"------------");
NSLog(@"%@", [self.lruCacheMap valueForKey:@"4"]);
[self.lruCacheMap enumerateKeysAndValuesUsingBlock:^(NSString *key, id obj, BOOL *stop) {
NSLog(@"key, value == %@, %@",key, obj);
}];
}
- (LRUCacheMap *)lruCacheMap{
if(_lruCacheMap == nil){
_lruCacheMap = [[LRUCacheMap alloc] initWithCapacity:5];
}
return _lruCacheMap;
}
c.運行結果
2020-05-22 14:47:01.414530+0800 LRUDemo[65621:2173464] key, value == 1, 100
2020-05-22 14:47:01.414716+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.414809+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.414905+0800 LRUDemo[65621:2173464] key, value == 4, 400
2020-05-22 14:47:01.414995+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.415076+0800 LRUDemo[65621:2173464] ------------
2020-05-22 14:47:01.415169+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.415272+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.415519+0800 LRUDemo[65621:2173464] key, value == 4, 400
2020-05-22 14:47:01.415698+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.416035+0800 LRUDemo[65621:2173464] key, value == 6, 600
2020-05-22 14:47:01.416124+0800 LRUDemo[65621:2173464] ------------
2020-05-22 14:47:01.416314+0800 LRUDemo[65621:2173464] 500
2020-05-22 14:47:01.416453+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.416681+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.416763+0800 LRUDemo[65621:2173464] key, value == 4, 400
2020-05-22 14:47:01.852132+0800 LRUDemo[65621:2173464] key, value == 6, 600
2020-05-22 14:47:01.852262+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.852345+0800 LRUDemo[65621:2173464] ------------
2020-05-22 14:47:01.852431+0800 LRUDemo[65621:2173464] 400
2020-05-22 14:47:01.852507+0800 LRUDemo[65621:2173464] key, value == 2, 200
2020-05-22 14:47:01.852596+0800 LRUDemo[65621:2173464] key, value == 3, 300
2020-05-22 14:47:01.852668+0800 LRUDemo[65621:2173464] key, value == 6, 600
2020-05-22 14:47:01.852760+0800 LRUDemo[65621:2173464] key, value == 5, 500
2020-05-22 14:47:01.852835+0800 LRUDemo[65621:2173464] key, value == 4, 400
Message from debugger: Terminated due to signal 15
Python源碼
a.源碼實現
from collections import OrderedDict
class LRUCacheMap(object):
def __init__(self, size):
super(LRUCacheMap, self).__init__()
# 總的容量大小
self.total_capcity = size
# 所有的鍵值對
self.cache_map = OrderedDict()
# 添加新值
def set_value(self, key, value):
if key in self.cache_map.keys():
# 當前值已經存在
value = self.cache_map.pop(key)
self.cache_map[key] = value
else:
# 新存入的值
if len(self.cache_map) == self.total_capcity:
# 超出最大值了 刪除棧裏第一個
self.cache_map.popitem(last = False)
else:
pass
# 添加新的值
self.cache_map[key] = value
def get_value(self, key):
# 判斷是否存在
if key in self.cache_map.keys():
value = self.cache_map.pop(key)
self.cache_map[key] = value
else:
value = None
return value
if __name__ == '__main__':
cache_map = LRUCacheMap(5)
for index in range(1, 6):
cache_map.set_value(str(index), index * 100)
print(cache_map.cache_map)
print('-' * 100 + '\n')
cache_map.set_value('6', 600)
print(cache_map.cache_map)
print('-' * 100 + '\n')
print(cache_map.get_value('5'))
print(cache_map.cache_map)
print('-' * 100 + '\n')
print(cache_map.get_value('4'))
print(cache_map.cache_map)
print('-' * 100 + '\n')
b.運行結果
OrderedDict([('1', 100), ('2', 200), ('3', 300), ('4', 400), ('5', 500)])
-------------------------------------------------------------------------
OrderedDict([('2', 200), ('3', 300), ('4', 400), ('5', 500), ('6', 600)])
-------------------------------------------------------------------------
500
OrderedDict([('2', 200), ('3', 300), ('4', 400), ('6', 600), ('5', 500)])
-------------------------------------------------------------------------
400
OrderedDict([('2', 200), ('3', 300), ('6', 600), ('5', 500), ('4', 400)])
-------------------------------------------------------------------------
[Finished in 0.0s]