Python + Redis 实现分布式锁


import threading
import time

import redis

redis_client = redis.Redis(host="localhost",
                           port=6379,
                           password="123456",
                           db=8)


class DistributedLock(object):

    def __init__(self, lock_name, lock_owner, expired=10):
        """
        :param lock_name: 锁的名称
        :param lock_owner: 锁的归属者
        :param expired: 锁的过期时间
        """
        self.lock_name = lock_name
        self.lock_owner = lock_owner
        self.expired = expired

    @staticmethod
    def _get_lock_name(lock_name):
        """
        拼接锁的名称
        :param lock_name: 旧的锁名称
        :return: String: 新的锁名称
        """
        lock_name = f'lock_{lock_name}'
        return lock_name

    def lock(self):
        """
        申请锁
        :return: boolean: True/False
        """
        _lock_name = self._get_lock_name(self.lock_name)
        # 申请锁的超时时间为600秒,可自行定义
        _timeout = 600
        # sleep的数值越小,支持的并发就越高
        _sleep_time = 0.0001
        # 系数
        _c = int(1 / _sleep_time)
        for _ in range(_timeout * _c):
            # 申请锁,用set()代替setnx(),set具有原子性,可以同时设置锁的过期时间
            # 给锁设置过期时间,防止死锁,例如防止程序意外崩溃不释放锁
            # set()成功返回True,失败返回None
            res = redis_client.set(_lock_name, self.lock_owner, nx=True, ex=self.expired)
            if res:
                return True
            else:
                time.sleep(_sleep_time)
        return False

    def del_lock(self):
        """
        释放锁
        :return: boolean: True/False
        """
        _lock_name = self._get_lock_name(self.lock_name)
        # 使用官方推荐的lua脚本进行释放锁,将判断锁的归属与删除锁合并成一个事务,进行原子性操作,防止高并发下误删除锁
        lua_script = """
        if redis.call("get",KEYS[1]) == ARGV[1] then
            return redis.call("del",KEYS[1])
        else
            return 0
        end
        """
        cmd = redis_client.register_script(lua_script)
        res = cmd(keys=[_lock_name], args=[self.lock_owner])
        return True if res == 1 else False


# demo
def _demo(_lock_name, _lock_owner):
    # 申请锁
    my_lock = DistributedLock(_lock_name, _lock_owner)
    my_lock.lock()

    # 业务代码
    global test_num
    test_num = test_num + 1
    thread_name = threading.current_thread().name
    print(f"{thread_name},数值:{test_num}")
    # time.sleep(0.5)

    # 释放锁
    my_lock.del_lock()


if __name__ == "__main__":
    # 测试用的数值
    test_num = 0
    _thread_count = 100  # 并发100
    _lock_name = 'my_lock_name'  # 锁的名称
    _lock_owner = 'liuyongzhan'  # 锁的归属者,这个值要确保唯一
    for i in range(_thread_count):
        thread = threading.Thread(target=_demo, args=(_lock_name, _lock_owner))
        thread.start()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值