redis 事务 多进程模拟秒杀 保证库存的正确 lua脚本和watch的方法

三种方法来实现

  1. lpop的 原子操作 10个商品就 lpush 10个数据 抢购开始用lpop来判断是否还存在库存

  2. watch实现 下面有代码实现
    watch库存键, multi后如果该key被其他客户端改变, 事务操作会抛出WatchError异常

  3. lua脚本 下面有代码实现

watch方法实现

import redis
from redis import WatchError
from concurrent.futures import ProcessPoolExecutor

r = redis.Redis(host='127.0.0.1', port=6379, password='123')


# 减库存函数, 循环直到减库存完成
# 库存充足, 减库存成功, 返回True
# 库存不足, 减库存失败, 返回False
def decr_stock():

    # python中redis事务是通过pipeline的封装实现的
    with r.pipeline() as pipe:
        while True:
            try:
                # watch库存键, multi后如果该key被其他客户端改变, 事务操作会抛出WatchError异常
                pipe.watch('stock:count')
                count = int(pipe.get('stock:count'))
                if count > 0:  # 有库存
                    # 事务开始
                    pipe.multi()
                    pipe.decr('stock:count')
                    # 把命令推送过去
                    # execute返回命令执行结果列表, 这里只有一个decr返回当前值
                    print pipe.execute()[0]
                    return True
                else:
                    return False
            except WatchError, ex:
                # 打印WatchError异常, 观察被watch锁住的情况
                print ex
                pipe.unwatch()


def worker():
    while True:
        # 没有库存就退出
        if not decr_stock():
            print "=============="
            break


# 实验开始
# 设置库存为100
r.set("stock:count", 100000)
print r.get("stock:count")
import time
testa = time.time()
# 多进程模拟多个客户端提交
with ProcessPoolExecutor(max_workers=5) as pool:
    for _ in range(10):
        pool.submit(worker)
print time.time() - testa

lua脚本的方法实现

import redis
from redis import WatchError
from concurrent.futures import ProcessPoolExecutor

r = redis.Redis(host='127.0.0.1', port=16379, password='joyame!@#')


# 减库存函数, 循环直到减库存完成
# 库存充足, 减库存成功, 返回True
# 库存不足, 减库存失败, 返回False
def decr_stock():
   lua_2 = """
        if (tonumber(redis.call("GET","stock:count")) > tonumber(0)) then
            redis.call("DECR","stock:count")
            return true
        else
            return nil
        end
        """

    # python中redis事务是通过pipeline的封装实现的
    with r.pipeline() as pipe:
        while True:
            try:
                script_2 = r.register_script(lua_2)
                a = script_2()
                if a >= 0:
                    print a
                    return True
                else:
                    return False

            except WatchError, ex:
                # 打印WatchError异常, 观察被watch锁住的情况
                print ex
                pipe.unwatch()


def worker():
    while True:
        # 没有库存就退出
        if not decr_stock():
            print "=============="
            break


# 实验开始
# 设置库存为100
r.set("stock:count", 1000)

import time
testa = time.time()
# 多进程模拟多个客户端提交
with ProcessPoolExecutor(max_workers=5) as pool:
    for _ in range(10):
        pool.submit(worker)
print time.time() - testa
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值