Python (Flask) 解決多進程(線程)併發操作redis 人爲加鎖(裝飾器和非裝飾器版)

import os

from flask_apscheduler import APScheduler
from flask_script import Manager
from redis import ConnectionPool

from app import create_app

# app = create_app(os.environ.get('futures') or 'default')
app = create_app(os.environ.get('futures') or 'testing')
manager = Manager(app)
# scheduler = APScheduler()

host = app.config['REDIS_HOST']
port = app.config['REDIS_PORT']
db = app.config['REDIS_DB']
redis_pool = ConnectionPool(host=host, port=port, db=db)

if __name__ == '__main__':
    # scheduler.init_app(app)
    # scheduler.start()
    manager.run()

import pickle
import time

import redis
from flask import current_app
from manage import redis_pool


def lock_redis_get(func):
    """ 裝飾器:給redis的get方法人爲加鎖 """

    def inner(cls, key):
        a = func(cls, key)
        if a:
            print(key, "直接查詢成功")
            return a
        else:
            flag_key = key + "flag"
            flag = MyRedis.get_eval(flag_key)
            if flag:
                while True:
                    print(key, "已經有其他線程在寫入")
                    time.sleep(0.5)
                    a = func(cls, key)
                    if a:
                        print(key, "等待查詢成功")
                        return a
            else:
                MyRedis.set(flag_key, True)
            return func(cls, key)

    return inner


class MyRedis(object):
    """
    redis數據庫操作
    """

    @staticmethod
    def _get_r():
        redis_instance = redis.StrictRedis(connection_pool=redis_pool)
        return redis_instance

    @classmethod
    def set(cls, key, value, expire=None):
        """
        寫入鍵值對
        """
        # 判斷是否有過期時間,沒有就設置默認值
        if expire:
            expire_in_seconds = expire
        else:
            expire_in_seconds = current_app.config['REDIS_EXPIRE']
        r = cls._get_r()
        # value = pickle.dumps(value)
        r.set(key, value, ex=expire_in_seconds)

    @classmethod
    # @lock_redis_get
    def get(cls, key):
        """
        讀取鍵值對內容
        """
        r = cls._get_r()
        value = r.get(key)
        return value.decode('utf-8') if value else value
        # return pickle.loads(value)

    @classmethod
    def lock_get(cls, key):
        """
        加鎖讀取鍵值對內容
        """
        r = cls._get_r()
        value = r.get(key)
        if value:
            return value.decode('utf-8')
        else:
            flag_key = key + "flag"
            flag = cls.get_eval(flag_key)
            if flag:
                while True:
                    print(key, "已經有其他線程在寫入")
                    time.sleep(0.5)
                    value = r.get(key)
                    if value:
                        print(key, "等待查詢成功")
                        return value.decode('utf-8')
            else:
                cls.set(flag_key, True)

    @classmethod
    def get_eval(cls, key):
        """
        讀取鍵值對內容
        """
        r = cls._get_r()
        value = r.get(key)
        val = value.decode('utf-8') if value else value
        try:
            re_val = eval(val)
            return re_val
        except Exception as e:
            return val

    @classmethod
    def hset(cls, name, key, value):
        """
        寫入hash表
        """
        r = cls._get_r()
        r.hset(name, key, value)

    @classmethod
    def hmset(cls, key, *value):
        """
        讀取指定hash表的所有給定字段的值
        """
        r = cls._get_r()
        value = r.hmset(key, *value)
        return value

    @classmethod
    def hget(cls, name, key):
        """
        讀取指定hash表的鍵值
        """
        r = cls._get_r()
        value = r.hget(name, key)
        return value.decode('utf-8') if value else value

    @classmethod
    def hgetall(cls, name):
        """
        獲取指定hash表所有的值
        """
        r = cls._get_r()
        return r.hgetall(name)

    @classmethod
    def keys(cls, pattern='*'):
        """
        獲取匹配到的鍵列表
        """
        r = cls._get_r()
        return r.keys(pattern)

    @classmethod
    def delete(cls, *names):
        """
        刪除一個或者多個
        """
        r = cls._get_r()
        r.delete(*names)

    @classmethod
    def hdel(cls, name, key):
        """
        刪除指定hash表的鍵值
        """
        r = cls._get_r()
        r.hdel(name, key)

    @classmethod
    def exists(cls, name):
        """
        判斷redis中是否存在某個key
        """
        r = cls._get_r()
        return r.execute_command('EXISTS', name)

    @classmethod
    def expire(cls, name, expire=None):
        """
        設置過期時間
        """
        if expire:
            expire_in_seconds = expire
        else:
            expire_in_seconds = current_app.config['REDIS_EXPIRE']
        r = cls._get_r()
        r.expire(name, expire_in_seconds)

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