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

  

posted @ 2020-11-11 15:20  关不上门  阅读(78)  评论(0编辑  收藏  举报