Python使用redis锁示例

Python使用redis锁示例

获取锁

单点执行

                # 如果不存在且设置成功返回1,否则返回0
                if cls._lock == 1:
                    cls.rdcon.setex(cls.lock_key, expire_time, now_time)
                    return True
                # 0,所以redislock_value一定有值
                elif now_time > redislock_value + redis_lock_timeout:
                    return False
                # 如果已存在则进行等待超时
                else:
                    time.sleep(0.3)

解析

  1. 如果redis中的key不存在,则返回1,这个时候直接使用,设置超时时间expire_time(用于最终兜底释放),返回一个标志位给到上层通知执行
  2. 如果redis中的key存在,判断是否超过锁时间redislock_value + RedisLockTimeout(只允许等待多久时间,不能无限制等待),如果超过,则返回一个标志位给到上层通知不执行(这里有个弊端:如果获取锁的那个节点执行失败一定要在RedisLockTimeout时间内,否则,其他节点无法重试),如果没超过,则继续进入等待

多节点依次执行

                # 如果不存在且设置成功返回1,否则返回0
                if cls._lock == 1 or now_time > redislock_value + redis_lock_timeout:
                    cls.rdcon.setex(cls.lock_key, expire_time, now_time)
                    return True
                # 如果已存在则进行等待超时
                else:
                    time.sleep(0.3)

解析

  1. 如果redis中的key不存在(这个时候有几种可能,一是第一次,二是上一个节点执行完毕,三是redis锁超过兜底逻辑expire_time),或者当前时间超过锁时间redislock_value + RedisLockTimeout这里有个弊端:会强行进入),则返回1,这个时候直接使用,设置超时时间expire_time(用于最终兜底释放),返回一个标志位给到上层通知执行
  2. 如果不满足第一点,则进入等待,直到满足为止

释放锁

    def release(cls):
        """
        释放锁

        :param cls:
        :return:
        """
        cls.rdcon.delete(cls.lock_key)

示例

参数设置

  • redis_lock_timeout超时时间:秒
  • is_wait是否限制依次执行:bool
  • expire_timeredis锁兜底超时:秒
# redis lock
import atexit
import time

import redis

RedisConfig = None
print("redis config:", RedisConfig)
RedisLockKey = "redis_lock_example"


class RedisLock(object):
    def __init__(self):
        self.rdcon = redis.StrictRedis(host=RedisConfig['host'], port=RedisConfig['port'],
                                       password=RedisConfig['password'], db=0, decode_responses=True)
        self._lock = 0
        self.lock_key = RedisLockKey

    @staticmethod
    def get_lock(cls, redis_lock_timeout=60, is_wait=True, expire_time=60 * 60):
        """
        expire_time: redis key过期时间,用于兜底最终释放
        """
        while cls._lock != 1:
            now_time = time.time()
            cls._lock = cls.rdcon.setnx(cls.lock_key, now_time)
            redislock_value = float(cls.rdcon.get(cls.lock_key))

            if is_wait:
                # 如果不存在且设置成功返回1,否则返回0
                if cls._lock == 1 or now_time > redislock_value + redis_lock_timeout:
                    cls.rdcon.setex(cls.lock_key, expire_time, now_time)
                    return True
                # 如果已存在则进行等待超时
                else:
                    time.sleep(0.3)
            else:
                # 如果不存在且设置成功返回1,否则返回0
                if cls._lock == 1:
                    cls.rdcon.setex(cls.lock_key, expire_time, now_time)
                    return True
                # 0,所以redislock_value一定有值
                elif now_time > redislock_value + redis_lock_timeout:
                    return False
                # 如果已存在则进行等待超时
                else:
                    time.sleep(0.3)

    @staticmethod
    def release(cls):
        """
        释放锁

        :param cls:
        :return:
        """
        cls.rdcon.delete(cls.lock_key)

def RedisLockDeco(cls):
    def _deco(func):
        def __deco(*args, **kwargs):
            is_continue = cls.get_lock(cls, redis_lock_timeout=60 * 5, is_wait=False)
            # 是否执行
            if is_continue:
                try:
                    return func(*args, **kwargs)
                finally:
                    atexit.register(cls.release, cls)
            else:
                return None

        return __deco

    return _deco

@RedisLockDeco(RedisLock())
def main():
    pass

本文作者:朝圣

本文链接:www.zh-noone.cn/2022/6/Python使用redis锁示例

版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0许可协议。转载请注明出处!

mysql由于null导致查询异常
0 条评论