python 如何解决高并发的问题

一个简单的使用场景:一件商品的库存只有5件,同时A用户买了5个,B用户买了5个,都提交数据,照成库存不足的问题。

    逻辑:根据一般电商商品的模型类,生成订单一般包括订单类(Order)和订单详情类(DetailOrder),这两张表根据外键order_id 进行关联,所以是同生共死的关系,所以我们在这里用事务来控制。那么python如何解决库存问题呢?

    python 提供了2种方法解决该问题的问题:1,悲观锁;2,乐观锁

    悲观锁:在查询商品储存的时候加锁 select_for_update()  在发生事务的commit或者是事务的rollback时,自动释放该锁,这样其他用户就可以接着查询该商品。

    乐观锁:乐观锁不是真正的锁,在创建订单之前查询商品的库存,在创建订单详情表前,update更新查询数据,如果两次查询的库存量一样就创建详情表,并减去库存,否则,循环三次,如果都不一样,就发生rollback。

    使用场景:并发量高的时候使用悲观锁,缺点:加锁消耗资源

                   并发量低的时候使用乐观锁,缺点:乐观锁循环耗费时间。

代码:

悲观锁:

@transaction.atomic
def post(self, request):
“”“接受数据 修改购物车数据 添加订单 和订单商品 加悲观锁 解决并发问题”""
sku_ids = request.POST.get(‘sku_ids’)
addr_id =request.POST.get(‘addr_id’)
pay_method = request.POST.get(‘pay_method’)
transit_price = request.POST.get(‘transit_price’)
user = request.user
if not user.is_authenticated(): # 判断是否登陆
return JsonResponse({‘res’: 0, ‘errmsg’: ‘用户未登录,请先登陆’})
try: # 判断地址是否存在
address = Customer.objects.get(id=addr_id)
except Customer.DoesNotExist:
return JsonResponse({‘res’: 1, ‘errmsg’: ‘地址不存在’})

    #  判断支付方式是否存在
    if pay_method not in OrderInfo.PAY_METHODS.keys():
        return JsonResponse({'res': 2, 'errmsg': '支付方式不存在'})
    total_price = 0
    total_count = 0
    order_id = datetime.now().strftime('%Y%m%d%H%M%S') + str(user.id)
    # 设置事务保存点
    tip = transaction.savepoint()
    try:
        new_order =OrderInfo.objects.create(order_id=order_id,
                                 user=user,
                                 addr=address,
                                 pay_method=pay_method,
                                 total_count=total_count,
                                 total_price=total_price,
                                 transit_price=transit_price)
    except Exception as e:
        # 回滚到tip
        transaction.savepoint_rollback(tip)
        return JsonResponse({'res': 3, 'errmsg': '生成订单失败'})
    cart_key = 'cart_%d' % user.id
    conn = get_redis_connection('default')
    skus = conn.hgetall(cart_key)
    for sku_id in eval(sku_ids):  # 循环获得商品的信息  每条数据生成一个订单商品数据
        # 获得购物车中每个商品的数量
        sku_count = conn.hget(cart_key, sku_id)
        if not sku_count:  # 判断购物车里有没有该商品
            # 回滚到tip
            transaction.savepoint_rollback(tip)
            return JsonResponse({'res': 4, 'errmsg': '该商品不在购物车中'})
        try:  # 在商品表中 找该商品sel
            sku = GoodsSKU.objects.select_for_update().get(id=sku_id, is_show=1)
        except GoodsSKU.DoesNotExist:
            # 回滚到tip
            transaction.savepoint_rollback(tip)
            return JsonResponse({'res': 5, 'errmsg': '该商品已下架'})
        price = sku.price
        sku_count = int(sku_count)
        if sku_count > int(sku.count):  # 判断库存
            # 回滚到tip
            transaction.savepoint_rollback(tip)
            return JsonResponse({'res': 6, 'errmsg': '库存不足'})
        price = int(price)
        sku_price = sku_count * price
        total_price += sku_price
        total_count += sku_count
        # 添加订单商品表
        try:
            OrderGoods.objects.create(order=new_order,
                                      sku=sku,
                                      count=sku_count,
                                      price=sku_price,
                                      )
        except Exception as e:
            # 回滚到tip
            transaction.savepoint_rollback(tip)
            return JsonResponse({'res': 7, 'errmsg': '订单商品创建失败'})
        # 减少商品库存 增加商品销售额
        sku.count -= sku_count
        sku.sale_count += sku_count
        sku.save()
        # 删除修改购物车数据
        conn.hdel(cart_key, sku_id)
    total_price += int(transit_price)
    # 修改order 订单数量 总价  邮费
    new_order.total_count = total_count
    new_order.total_price = total_price
    new_order.transit_price = transit_price
    new_order.save()
    #释放保存点

    transaction.savepoint_commit(tip)

乐观锁:

      @transaction.atomic
def post(self, request):
    '''订单创建'''
    # 判断用户是否登录
    user = request.user
    if not user.is_authenticated():
        return JsonResponse({'res':0, 'errmsg':'用户未登录'})
    # 接收参数
    addr_id = request.POST.get('addr_id')
    pay_method = request.POST.get('pay_method')
    sku_ids = request.POST.get('sku_ids') # 1,4
    # 校验参数
    if not all([addr_id, pay_method, sku_ids]):
        return JsonResponse({'res':1, 'errmsg':'数据不完整'})
    # 校验地址
    try:
        addr = Address.objects.get(id=addr_id)
    except Address.DoesNotExist:
        # 地址不存在
        return JsonResponse({'res':2, 'errmsg':'地址信息错误'})
    # 校验支付方式
    if pay_method not in OrderInfo.PAY_METHODS.keys():
        # 支付方式无效
        return JsonResponse({'res':3, 'errmsg':'支付方式无效'})
    # 业务处理:订单创建
    # 组织参数
    # 订单id(order_id): 20171211123130+用户的id
    order_id = datetime.now().strftime('%Y%m%d%H%M%S')+str(user.id)
    # 运费
    transit_price = 10
    # 总数目和总金额
    total_count = 0
    total_price = 0
    # 设置保存点
    sid = transaction.savepoint()
    try:
        # todo: 向df_order_info表中添加一条记录
        order = OrderInfo.objects.create(order_id=order_id,
                                         user=user,
                                         addr=addr,
                                         pay_method=pay_method,
                                         total_count=total_count,
                                         total_price=total_price,
                                         transit_price=transit_price)
        conn = get_redis_connection('default')
        cart_key = 'cart_%d'%user.id
        # todo: 用户的订单中包含几个商品,就应该向df_order_goods中添加几条记录
        sku_ids = sku_ids.split(',') # [1,4]
        for sku_id in sku_ids:
            for i in range(3):
                # 根据sku_id获取商品的信息
                try:
                    # select * from df_goods_sku where id=sku_id;
                    sku = GoodsSKU.objects.get(id=sku_id)
                except GoodsSKU.DoesNotExist:
                    transaction.savepoint_rollback(sid)
                    return JsonResponse({'res':4, 'errmsg':'商品信息错误'})
                # 获取用户要购买的商品的数目
                count = conn.hget(cart_key, sku_id)
                # todo: 判断商品库存
                if int(count) > sku.stock:
                    transaction.savepoint_rollback(sid)
                    return JsonResponse({'res':6, 'errmsg':'商品库存不足'})
                # todo: 减少商品的库存,增加销量
                origin_stock = sku.stock
                new_stock = origin_stock - int(count)
                new_sales = sku.sales + int(count)
                # print('user:%d i:%d stock:%d'%(user.id, i, origin_stock))
                # import time
                # time.sleep(10)
                # 返回更新的行数
                # update df_goods_sku set stock=new_stock, sales=new_sales
                # where id=sku_id and stock=origin_stock
                res = GoodsSKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                if res == 0:
                    # 更新失败
                    if i == 2:
                        # 已经尝试了3次,下单失败
                        transaction.savepoint_rollback(sid)
                        return JsonResponse({'res':7, 'errmsg':'下单失败2'})
                    continue
                # todo: 向df_order_goods中添加一条记录
                OrderGoods.objects.create(order=order,
                                          sku=sku,
                                          count=count,
                                          price=sku.price)
                # todo: 累加计算商品的总件数和总金额
                total_count += int(count)
                total_price += sku.price*int(count)
                # 更新成功之后跳出循环
                break
        # todo: 更新order的total_count和total_price
        order.total_count = total_count
        order.total_price = total_price
        order.save()
    except Exception as e:
        transaction.savepoint_rollback(sid)
        return JsonResponse({'res':7, 'errmsg':'下单失败'})
    # 释放保存点
    transaction.savepoint_commit(sid)
    # todo: 删除购物车对应记录信息
    conn.hdel(cart_key, *sku_ids) # 1,4
    # 返回应答
    return JsonResponse({'res':5, 'message':'订单创建成功'})

tip:使用乐观锁时,记得修改mysql的隔离级别:vi /etc/mysql/mysql.conf.d/mysqld.cnf 在mysqld最下面一行添加:transaction-isolation = READ_COMMITTED 。

### 回答1: 对于 Python 项目的高并发设计,可以采用多线程或多进程的方式来实现。 多线程可以通过 Python 标准库中的 `threading` 模块来实现,优点是简单易用,缺点是 Python 的 Global Interpreter Lock (GIL) 会限制多线程的性能。 多进程可以通过 Python 标准库中的 `multiprocessing` 模块来实现,优点是可以充分利用多核 CPU 的性能,缺点是进程间通信和数据共享比较复杂。 还可以使用第三方库如 asyncio,gevent,concurrent.futures等来实现高并发 此外,还可以采用服务器端框架(如 Flask, Django, Tornado 等)来实现高并发。 ### 回答2: 在Python项目的高并发设计中,有几个关键的方面需要考虑。 首先,需要使用适当的并发编程模型。Python提供了多种并发编程模型,如多线程、多进程、协程等。在选择合适的模型时,需要考虑项目的具体需求和性能要求。比如,如果项目需要处理大量的IO操作,可以选择使用协程,因为它能够高效地处理并发的IO操作。 其次,需要充分利用Python提供的并发相关的库和工具。Python提供了一些功能强大的库和工具,如asyncio、gevent、multiprocessing等。这些库和工具能够帮助我们实现高效的并发设计。比如,使用asyncio库可以轻松地编写异步并发的代码;使用multiprocessing库可以方便地进行多进程并发处理。 另外,要进行合适的资源管理和优化。高并发的项目通常需要管理大量的资源,如内存、数据库连接、网络带宽等。合理地管理这些资源可以提升项目的性能和并发能力。比如,可以使用连接池技术来管理数据库连接,减少连接的创建和关闭的开销;可以使用缓存来减轻对数据库和其他资源的访问压力。 最后,还需要进行适当的性能测试和优化。通过性能测试可以找到项目的瓶颈和瓶颈所在,然后根据测试结果进行优化。比如,可以通过优化算法、增加服务器的硬件资源、使用负载均衡等方式来提高项目的并发能力和性能。 综上所述,在Python项目的高并发设计中,需要选择合适的并发编程模型,充分利用Python提供的并发相关的库和工具,进行合适的资源管理和优化,以及进行适当的性能测试和优化。这些措施能够帮助我们实现高效、稳定的高并发项目。 ### 回答3: Python项目高并发设计是指在开发过程中,考虑到项目可能面临大量并发请求的情况下,采取一系列措施来提高项目的并发能力和性能。 首先,可以通过使用多线程或多进程来实现并发处理。Python的多线程模块threading或多进程模块multiprocessing可以很好地支持并发,将处理任务分配给多个线程或进程同时执行,提高项目的并发能力。 其次,可以利用协程来实现高并发。协程是一种轻量级的线程,可以在单线程内实现多个任务的切换,提高并发处理的效率。Python中的协程库asyncio提供了对协程的支持,可以利用协程来实现高并发的项目设计。 另外,可以使用消息队列来实现高并发。消息队列可以实现任务的异步处理,将大量请求放入消息队列中,再由多个消费者并发地处理这些请求,减轻单个服务器的压力,提高并发能力和性能。 还可以使用缓存来提高项目的并发处理能力。通过将频繁请求的数据或计算结果缓存起来,可以减少对数据库或其他数据源的访问,提高响应速度,提高项目的并发能力。 另外,可以对数据库进行优化,如建立索引、合理使用数据库连接池等,提高数据库的并发性能。 此外,在项目开发中,还需要考虑到并发请求可能引发的问题,如资源竞争、死锁等,需要合理地设计并发控制机制来解决这些问题。 总之,Python项目高并发设计需要综合考虑多方面的因素,包括多线程、协程、消息队列、缓存、数据库优化等,通过合理的设计和技术选型,来提高项目的并发能力和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值