关于《redis实战》中6-9代码片段使用setex锁的不解
想了很久,实在不能理解代码清单6-9中锁的使用原理,锁只是设置了一个key,而且完全没有用到(比如if getkey()==true之类的),生成的锁还是随机的,也就是不还是没解决并发的问题吗? 同一时间仍然有可能会有其他客户端对数据进行操作。
求大佬解惑,谢谢。
# 代码清单 6-8
# <start id="_1314_14473_8641"/>
def acquire_lock(conn, lockname, acquire_timeout=10):
# 128位随机标识符。
identifier = str(uuid.uuid4())
end = time.time() + acquire_timeout
while time.time() < end:
# 尝试取得锁。
if conn.setnx('lock:' + lockname, identifier):
return identifier
time.sleep(.001)
return False
# <end id="_1314_14473_8641"/>
# 代码清单 6-9
# <start id="_1314_14473_8645"/>
def purchase_item_with_lock(conn, buyerid, itemid, sellerid):
buyer = "users:%s" % buyerid
seller = "users:%s" % sellerid
item = "%s.%s" % (itemid, sellerid)
inventory = "inventory:%s" % buyerid
# 尝试获取锁。
locked = acquire_lock(conn, 'market:')
if not locked:
return False
pipe = conn.pipeline(True)
try:
# 检查物品是否已经售出,以及买家是否有足够的金钱来购买物品。
pipe.zscore("market:", item)
pipe.hget(buyer, 'funds')
price, funds = pipe.execute()
if price is None or price > funds:
return None
# 将买家支付的货款转移给卖家,并将售出的物品转移给买家。
pipe.hincrby(seller, 'funds', int(price))
pipe.hincrby(buyer, 'funds', int(-price))
pipe.sadd(inventory, itemid)
pipe.zrem("market:", item)
pipe.execute()
return True
finally:
# 释放锁。
release_lock(conn, 'market:', locked)
# <end id="_1314_14473_8645"/>
# 代码清单 6-10
# <start id="_1314_14473_8650"/>
def release_lock(conn, lockname, identifier):
pipe = conn.pipeline(True)
lockname = 'lock:' + lockname
while True:
try:
# 检查并确认进程还持有着锁。
pipe.watch(lockname)
if pipe.get(lockname) == identifier:
# 释放锁。
pipe.multi()
pipe.delete(lockname)
pipe.execute()
return True
pipe.unwatch()
break
# 有其他客户端修改了锁;重试。
except redis.exceptions.WatchError:
pass
# 进程已经失去了锁。
return False
# <end id="_1314_14473_8650"/>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请仔细查看一下手册,setnx命令是如果当前redis中没有设置的key才会设置成功返回1,否则设置失败返回0,把它当成锁使用,就是利用了这个特性,至于设置什么值关系不大。
单从例子上看,acquire_lock 中使用了setnx,只有一个操作可以锁定成功。而且redis是单进程的,所有命令都是一个接着一个串行处理。所以不觉得有什么并发问题