Redis--实现分布式锁

Redis分布式锁实现的方式:setnx
查看redis库的源码:

    def setnx(self, name, value):
        "Set the value of key ``name`` to ``value`` if key doesn't exist"
        return self.execute_command('SETNX', name, value)

setnx方法只有在key不存在时才能设置成功,否则设置失败。
设置成功时返回True,设置失败时返回False
具体思路:

首先定义一个RedisLock类,实现加锁功能。
__init__方法初始化redis的connect、是否加锁的Flag以及锁名。
get_lock方法目的是获取锁资源,主要思想是通过redissetnx方法的返回值来判断,当返回True时,表示加锁成功,当返回False时,表示加锁失败。锁名作为key,过期时间作为value。如果获取的value小于当前时间,则表示该lock已过期,同样可以获得锁资源。
release方法目的是释放锁资源。
最后定义一个有参装饰器,给需要加锁的方法或函数加锁。

Demo代码:

import time
import redis


class RedisLock(object):
    def __init__(self, key):
        # redis的连接,官方推荐ssshi用StrictRedis,而不是Redis
        self.rdcon = redis.StrictRedis(host='127.0.0.1', port=6379, password="", db=1, decode_responses=True)
        print(id(self.rdcon))
        # False代表未加锁,True代表加锁了
        self._lock = False
        # lock名字
        self.lock_key = "%s_dynamic_test" % key

    @staticmethod
    def get_lock(cls, timeout=10):
        while not cls._lock:
            print('try to get lock')
            # 过期时间,将作为lock_key的value
            timestamp = time.time() + timeout + 1
            # 设置lock_key,value为过期时间
            # 注:加锁成功返回Ture,加锁失败返回False
            cls._lock = cls.rdcon.setnx(cls.lock_key, timestamp)

            # 注意下方括号的范围,如果当前时间大于lock_key的value,那么也就是lock_key过期了
            if cls._lock or (time.time() > float(cls.rdcon.get(cls.lock_key)) and
                             time.time() > float(cls.rdcon.getset(cls.lock_key, timestamp))):

                print("get lock")
                break
            else:
                time.sleep(1)

    @staticmethod
    def release(cls):
        # 释放锁资源,即使lock_key未过期,也要释放锁资源
        if time.time() < float(cls.rdcon.get(cls.lock_key)):
            print("release lock")
            cls.rdcon.delete(cls.lock_key)


# 装饰器,用来加锁的装饰器
def deco(cls):
    def _deco(func):
        def __deco(*args, **kwargs):
            # 查看对象及地址
            print("before %s called [%s]." % (func.__name__, cls))
            # 装饰器传入的参数为redis的lock对象,调用get_lock方法,同时把自己当作参数传入
            cls.get_lock(cls)
            try:
                return func(*args, **kwargs)
            finally:
                cls.release(cls)

        return __deco

    return _deco


@deco(RedisLock("lock_key"))
def myfunc():
    print("myfunc() called.")
    time.sleep(5)


if __name__ == "__main__":
    myfunc()

你可能感兴趣的:(Redis--实现分布式锁)