zoukankan      html  css  js  c++  java
  • 基于redis实现分布式锁

    import time
    import uuid
    import redis
    from threading import Thread
    
    redis_client = redis.Redis(host='localhost', port=6379)
    
    
    # 获取一个锁
    def acquicre_lock(lock_name, acquice_time=10, time_out=10):
        """
        获取一个分布式锁
        :param lock_name: 锁名称
        :param acquice_time: 客户端等待获取锁的时间
        :param time_out: 锁的超时时间
        :return:
        """
        # 生成唯一id
        identifier = str(uuid.uuid4())
        # 客户端获取锁的结束时间
        end = time.time() + acquice_time
        # key
        lock = 'string:lock:' + lock_name
        while time.time() < end:
            # setnx(key, value) 只有key不存在情况下,将key值设置为value,若key存在则不做任何动作,返回True和False
            if redis_client.setnx(lock, identifier):
                # 给锁设置超时时间,防止进程崩溃导致其他进程无法获取锁
                redis_client.expire(lock, time_out)
                return identifier
            # 当锁未被设置过期时间时,重新设置其过期时间
            elif not redis_client.ttl(lock):
                redis_client.expire(lock, time_out)
            time.sleep(0.001)
        return False
    
    
    # 释放一个锁
    def release_lock(lock_name, identifier):
        """
        通用的锁释放函数
        """
        lock = 'string:lock:' + lock_name
        pip = redis_client.pipeline(True)
        while True:
            try:
                # 通过watch命令监视某个键,当该键未被其他客户端修改值时,事务成功执行,当事务运行过程中,发现该值被其他客户端更新了值,任务失败
                pip.watch(lock)
                lock_value = redis_client.get(lock)
                if not lock_value:
                    return True
                if lock_value.decode() == identifier:
                    # multi命令用于开启一个事务,它总是返回ok
                    # multi执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC 命令被调用时, 所有队列中的命令才会被执行
                    pip.multi()
                    # 删除键,释放锁
                    pip.delete(lock)
                    # execute命令负责触发并执行事务中的所有命令
                    pip.execute()
                    return True
                pip.unwatch()
                break
            except redis.exceptions.WatchError:
                # 释放锁期间,有其他客户端改变了键值对,锁释放失败,进行循环
                pass
        return False
    
    
    count = 10
    
    
    def seckill(i):
        identifier = acquicre_lock('resource')
        print('线程:{}--获得了锁'.format(i))
        time.sleep(1)
        global count
        if count < 1:
            print('线程:{}--没抢到,票抢完了'.format(i))
            return
        count -= 1
        print('线程:{}--抢到一张票,还剩下{}张票'.format(i, count))
        release_lock('resource', identifier)
    
    
    for i in range(50):
        t = Thread(target=seckill, args=(i,))
        t.start()
    

      

  • 相关阅读:
    centos7 docker安装awvs
    screen命令简介-实现linux多窗口
    linux命令重命名
    iptables防止nmap扫描
    cobal strike could not start listener address already in use (bind failed)
    docker简介及安装
    「Sqlserver」数据分析师有理由爱Sqlserver之二-像使用Excel一般地使用Sqlserver
    「Sqlserver」数据分析师有理由爱Sqlserver之一-好用的插件工具推荐
    「PowerBI」分析服务多维数据结构重回关系数据库的一大绝招
    「数据分析」Sqlserver中的窗口函数的精彩应用之数据差距与数据岛(含答案)
  • 原文地址:https://www.cnblogs.com/weiwuhu/p/13958888.html
Copyright © 2011-2022 走看看