Python基於單例模式實現具有時效性的內存緩存

Python基於單例模式實現具有時效性的內存緩存

版本說明:Python 2.7

Python有不少第三方的緩存庫,如cacheoutmemcached等。因爲項目需求,這裏不使用第三方庫,自己實現具有時效性的內存緩存,用來緩存重複利用的數據。

1 設計實現

1.1 思路

採用dict()作爲緩存介質,數據以key、value的形式進行保存。key爲cache_id,用來標識不同的緩存數據。value是要進行緩存的數據。並且使用單例的設計模式,保障緩存數據的原子性。在時效性控制上,對每一個緩存數據進行單獨控制,使用threading.Timer進行延時銷燬緩存數據。

1.2 設計單例模式

本例子使用__new__關鍵字實現單例模式。如下所示:

# encoding: utf-8
"""
Created by shirukai on 2018/11/7
"""
import threading


class DataCache(object):
    # 添加線程鎖,保證多線程安全
    __instance_lock = threading.Lock()

    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):

        if not hasattr(DataCache, "_instance"):
            with DataCache.__instance_lock:
                if not hasattr(DataCache, "_instance"):
                    DataCache._instance = object.__new__(cls)
        return DataCache._instance

測試:

if __name__ == '__main__':
    for i in xrange(10):
        print DataCache()

1.3 時效性控制

在時效性控制上,選用了threading.Timer進行延時執行方法。例如我要延時執行一個打印方法,可以使用如下的代碼.

# encoding: utf-8
"""
Created by shirukai on 2018/11/7
"""
import threading
import time


def print_str(string):
    print string


if __name__ == '__main__':
    timer = threading.Timer(2, print_str, ['test timer'])
    timer.start()
    time.sleep(10)

Timer(延時時間,執行函數,參數)

2 實現代碼

# encoding: utf-8
"""
Created by shirukai on 2018/11/5
基於單例模式實現具有時效性的內存緩存
"""
import threading
import uuid


class DataCache(object):
    """
    _cache 的數據結構如下所示:
    _cache:{
        "cache_id_1":{
            "value":"cache_value",
            "expired":"60s",
            "timer":"定時清理器實例",
        }
    }
    """

    # 默認 expired = 2*60*60s
    EXPIRED = 2 * 60 * 60

    # 添加線程鎖,保證多線程安全
    __instance_lock = threading.Lock()

    # 初始化dict()用來緩存數據
    __CACHE = dict()

    def __init__(self):
        self.__cache = DataCache.__CACHE

    def __new__(cls, *args, **kwargs):

        if not hasattr(DataCache, "_instance"):
            with DataCache.__instance_lock:
                if not hasattr(DataCache, "_instance"):
                    DataCache._instance = object.__new__(cls)
        return DataCache._instance

    def set(self, value, cache_id=None, expired=EXPIRED):
        """
        保存緩存
        :param value: 緩存數據
        :param cache_id: cache_id 默認值:None
        :param expired: 過期時間 默認值:EXPIRED
        :return: cache_id
        """
        if cache_id is None or cache_id == "":
            cache_id = str(uuid.uuid4())

        self._set_cache(value, cache_id, expired)

        return cache_id

    def delete(self, cache_id):
        """
        刪除緩存
        :param cache_id: 緩存ID
        :return: None
        """
        self._clean_cache(cache_id)

    def get(self, cache_id):
        """
        獲取緩存
        :param cache_id:緩存ID
        :return:
        """
        if self.__cache.has_key(cache_id):
            return self.__cache[cache_id]['value']
        else:
            return None

    def values(self):
        """
        獲取所有值
        :return: {
        “cache_id_1”:"value1",
        “cache_id_2”:"value2"
        }
        """
        return {key: item['value'] for key, item in self.__cache.items()}

    def clear(self):
        """
        清空緩存
        :return: None
        """
        for cache_id in self.__cache.keys():
            self._clean_cache(cache_id)

    def _set_cache(self, value, cache_id, expired):
        # 刪除緩存
        self._clean_cache(cache_id)
        # 設置時效監控線程
        timer = threading.Timer(expired, self._clean_cache, [cache_id])
        timer.start()
        self.__cache[cache_id] = {
            'timer': timer,
            'value': value
        }

    def _clean_cache(self, cache_id):
        if self.__cache.has_key(cache_id):
            timer = self.__cache[cache_id]['timer']
            timer.cancel()
            self.__cache.pop(cache_id)

3 測試

測試代碼:

# encoding: utf-8
"""
Created by shirukai on 2018/11/7
"""
from src.api.v1.cache.data_cache import DataCache
import time

if __name__ == '__main__':
    cache = DataCache()
    # 保存一個字符串,並設置時效性爲6秒
    cache_id = cache.set(value="test cache!", expired=6)

    # 每隔一秒打印一次數據
    for i in xrange(10):
        print cache.get(cache_id)
        time.sleep(1)

效果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章