关于《redis实战》中6-9代码片段使用setex锁的不解

发布于 2022-09-07 11:48:17 字数 2507 浏览 17 评论 0

想了很久,实在不能理解代码清单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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

江心雾 2022-09-14 11:48:17

请仔细查看一下手册,setnx命令是如果当前redis中没有设置的key才会设置成功返回1,否则设置失败返回0,把它当成锁使用,就是利用了这个特性,至于设置什么值关系不大。

深海少女心 2022-09-14 11:48:17

单从例子上看,acquire_lock 中使用了setnx,只有一个操作可以锁定成功。而且redis是单进程的,所有命令都是一个接着一个串行处理。所以不觉得有什么并发问题

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文