基于redis的分布式锁--python实现

直接上代码

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

实际还存在一个问题,如果任务的执行时间超过了锁的有效期,就会导致其他进程获取锁,会出现释放的锁并非当前任务加的锁的情况,这里可以另开一个线程在一定时间内不断为锁续命。

猜你喜欢

转载自www.cnblogs.com/82nlf-xlqb/p/12116167.html