直接上代码
1 # coding=utf-8 2 3 4 # 使用redis实现分布式锁的原因 5 # 1 redis性能好 6 # 2 redis命令对此支持较好,实现起来比较方便 7 8 """ 9 redis命令介绍 10 setnx key val 当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0 11 expire key timeout 为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁 12 delete key 删除key 13 """ 14 import time 15 import uuid 16 from threading import Thread 17 18 import redis 19 20 redis_client = redis.Redis(host="localhost", port=6379, db=2) 21 22 23 def acquire_lock(lock_str, acquire_time=10, time_out=10): 24 """设置锁""" 25 lock_key = "string:lock:" + lock_str 26 identifier_uuid_str = str(uuid.uuid4()) 27 end = time.time() + acquire_time 28 29 try: 30 while time.time() < end: 31 if redis_client.setnx(lock_key, identifier_uuid_str): 32 # 设置超时时间,防止进程崩溃导致其他进程无法获取锁 33 redis_client.expire(lock_key, time=time_out) 34 return identifier_uuid_str 35 36 elif not redis_client.ttl(lock_key): 37 redis_client.expire(lock_key, time=time_out) 38 time.sleep(0.01) 39 finally: 40 # 释放锁 41 redis_client.delete(lock_key) 42 return False 43 44 45 def release_lock(lock_str, identifier_uuid_str): 46 """释放锁""" 47 lock = "string:lock:" + lock_str 48 pip = redis_client.pipeline(True) 49 while True: 50 try: 51 pip.watch(lock) 52 lock_value = redis_client.get(lock) 53 if not lock_value: 54 return True 55 56 if lock_value.decode() == identifier_uuid_str: 57 pip.multi() 58 pip.delete(lock) 59 pip.execute() 60 return True 61 pip.unwatch() 62 break 63 except redis.exceptions.WatchError: 64 pass 65 return False 66 67 68 # 秒杀demo 69 def seckill(product_id, t_id): 70 identifier_uuid_str = acquire_lock(product_id) 71 if not identifier_uuid_str: 72 return "error" 73 print "线程:{}--获得了锁".format(t_id) 74 stock = int(redis_client.get("stock")) 75 if stock > 0: 76 real_stock = stock - 1 77 redis_client.set("stock", str(real_stock)) 78 print "线程:{}--抢到一件商品,剩余库存{}件".format(t_id, real_stock) 79 else: 80 print "线程:{}--没抢到,库存不足".format(t_id) 81 return 82 release_lock(product_id, identifier_uuid_str) 83 print "线程:{}--释放了锁".format(i) 84 85 86 # redis-cli: set stock 20 87 for i in range(25): 88 product_id = "product_001" 89 t = Thread(target=seckill, args=(product_id, i,)) 90 t.start()
实际还存在一个问题,如果任务的执行时间超过了锁的有效期,就会导致其他进程获取锁,会出现释放的锁并非当前任务加的锁的情况,这里可以另开一个线程在一定时间内不断为锁续命。
原文地址:https://www.cnblogs.com/82nlf-xlqb/p/12116167.html
时间: 2024-10-10 03:47:14