看完这节课的一些疑问

来源:34-2 什么是分布式锁

城中城

2022-06-28

老师你可以直接复制下面代码运行看看
或者自己改一下即可 在释放锁后 添加一个等待时间

from datetime import datetime

from peewee import *

from inventory_srv.settings import settings


# 删除 物理删除和逻辑删除 - 物理删除 - 假设你把某个用户数据 - 用户购买记录, 用户的收藏记录, 用户浏览记录啊
# 通过 save 方法做了修改 如何确保只修改 update_time 值而不是修改 add_time
class BaseModel(Model):
    add_time = DateTimeField(default=datetime.now, verbose_name="添加时间")
    update_time = DateTimeField(default=datetime.now, verbose_name="更新时间")
    is_deleted = BooleanField(default=False, verbose_name="是否删除")

    def save(self, *args, **kwargs):
        # 判断这是一个新添加的数据还是更新的数据
        if self._pk is not None:
            # 这是一个新数据
            self.update_time = datetime.now()
        return super().save(*args, **kwargs)

    @classmethod
    def delete(cls, permanently=False):   # permanently 表示是否永久删除
        if permanently:
            return super().delete()
        else:
            return super().update(is_deleted=True)

    def delete_instance(self, permanently=False, recursive=False, delete_nullable=False):
        if permanently:
            return self.delete(permanently).where(self._pk_expr()).execute()
        else:
            self.is_deleted = True
            self.save()

    @classmethod
    def select(cls, *fields):
        return super().select(*fields).where(cls.is_deleted==False)

    class Meta:
        database = settings.DB


# class Stock(BaseModel):
#     # 仓库表
#     name = CharField(verbose_name="仓库名")
#     address = CharField(verbose_name="仓库地址")


class Inventory(BaseModel):
    # 商品的库存表
    # stock = PrimaryKeyField(Stock)
    goods = IntegerField(verbose_name="商品id", unique=True)      # unique:在此列上创建唯一索引
    stocks = IntegerField(verbose_name="库存数量", default=0)
    version = IntegerField(verbose_name="版本号", default=0)       # 分布式锁的一种 乐观锁

import  threading

R = threading.Lock()

def sell():
    # 多线程下的并发带来的数据不一致的问题
    goods_list = [(421, 99), (422, 20), (423, 30)]
    with settings.DB.atomic() as txn:
        # 超卖
        for goods_id, num in goods_list:
            # 查询库存
            R.acquire()     # 获取锁 负载均衡
            goods_inv = Inventory.get(Inventory.goods==goods_id)
            print(f"商品{goods_id} 售出 {num} 件")
            import time
            from random import randint
            time.sleep(randint(1, 3))
            if goods_inv.stocks < num:
                print(f"商品: {goods_id} 库存不足")
                txn.rollback()
                R.release()  # 释放锁
                break
            else:
                # 让数据库根据自己当前的值更新数据, 这个语句能不能处理并发的问题
                query = Inventory.update(stocks=Inventory.stocks-num).where(Inventory.goods==goods_id)
                ok = query.execute()
                if ok:
                    print("更新成功")
                else:
                    print("更新失败")
            R.release()     # 释放锁
            time.sleep(1)


if __name__ == '__main__':
    import threading

    t1 = threading.Thread(target=sell)
    t2 = threading.Thread(target=sell)
    t1.start()
    t2.start()

    t1.join()
    t2.join()


只是在老师的代码 稍微 更改一下 还是一样有着相同的问题
比如 我在释放锁后 等待一些时间
导致 线程1产生 io操作 被线程2争取
这样就比 超卖还要严重 导致锁无法被释放的问题
请问 这样如何解决
因为真正的生产环境中 极有可能会遇到这类问题

写回答

1回答

bobby

2022-06-28

线程2拿到锁了, 线程二就扣减就行了, 为什么会导致锁无法释放?

0
2
城中城
这个问题 我差不多以及知道了 是因为 我偷懒 使用这个 settings.DB.atomic() 的问题 导致的 相同的问题 类似 如上面的url
2022-06-28
共2条回复

Go+Python打造电商系统 自研微服务框架 抓紧高薪机遇

快速转型Go工程师,成为具备双语言后端能力的开发者

510 学习 · 530 问题

查看课程