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()

iimport 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"
            while True:
                flag = MyRedis.get_eval(flag_key)
                if flag:
                    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"
            while True:
                flag = cls.get_eval(flag_key)
                if flag:
                    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, expire=120)
                    return

    @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 delete_start_with(cls, key_prefix):
        """
        根据前缀删除key
        """
        pattern = key_prefix + "*"
        my_keys = cls.keys(pattern)
        for k in my_keys:
            cls.delete(k)

    @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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值