秒杀的小疑问

秒杀的小疑问

import random
import time
from concurrent.futures.thread import ThreadPoolExecutor

import redis
from redis_connect import pool


# 生成用户ID函数
def create_id():
    u_list = []
    while True:
        u_id = random.randint(10000, 1000000)
        if u_id in u_list and len(u_list) < 500:
            continue
        else:
            if len(u_list) < 500:
                # print(len(u_list))
                u_list.append(u_id)
            else:
                break
    return u_list


# 生成模拟用户id列表
u_list = create_id()
j_list = []


def set_default_key():
    con = redis.Redis(connection_pool=pool)
    con.delete("goods", "user_id")
    con.hmset("goods", {"商品名称": "苹果手机", "商品数量": 500,
                        "秒杀数量": 0})
    # 设置秒杀时间,秒杀标志位,10秒
    con.setex("flag", 10, 1)


# 商品秒杀
def kill_goods():
    try:
        con = redis.Redis(connection_pool=pool)
        pipe = con.pipeline()
        pipe.watch("goods", "flag")
        pipe.multi()
        s_num = int(pipe.hget("goods", "商品数量").execute()[0].decode("utf-8"))
        k_num = int(pipe.hget("goods", "秒杀数量").execute()[0].decode("utf-8"))
        k_flag = int(pipe.exists("flag").execute()[0])
        # print(s_num)
        # print(k_num)
        # print(k_flag)
        # print(g_name)
        # print(k_flag)
        global j_list
        # 判断用户id重复
        while True:
            # 从列表中随机取出一个用户id
            u_id = u_list[random.randint(0, 499)]
            # 如果不在新列表中则加入,或者新列表长度为500时,break
            if u_id not in j_list or len(j_list) == 500:
                j_list.append(u_id)
                break
            # 否则就认定id重复,跳出此次循环,再次生成新id判断
            else:
                continue
        # 如果商品总数-秒杀数大于0,且秒杀位存在,说明可以继续秒杀
        if s_num - k_num > 0 and k_flag == 1:
            pipe.rpush("user_id", u_id)
            pipe.hincrby("goods", "秒杀数量", 1)
            print("秒杀还剩{}件".format(s_num - k_num))
        # 如果商品总数-秒杀数等于0,且秒杀位还存在,说明商品被秒杀完了
        elif s_num - k_num == 0 and k_flag == 1:
            print("商品秒杀空了")
        # 如果秒杀位不存在,说明时间到
        elif k_flag == 0:
            print("秒杀时间到,秒杀结束")
        pipe.execute()
    except Exception as e:
        print(e)
    finally:
        if "pipe" in dir():
            pipe.reset()
        del con


# 设置商品默认key
set_default_key()
# 开启多线程秒杀
with ThreadPoolExecutor(max_workers=10) as executor:
    for i in range(500):
        executor.submit(kill_goods)

关于最后的多线程使用

问题1、

with ThreadPoolExecutor(max_workers=10) as executor: 可否理解为,10个人同时请求秒杀

而里面的for循环理解为商品数量有500件。

问题2、这样的代码会出现Watched variable changed.提示。可否理解为:多个线程在修改秒杀商品数量个数的时候,有可能线程之间操作数据的冲突(watch了goods这个key)。一旦在某个线程的事务操作goods没有exec之前,另一个线程的事务又来操作goods,这就会导致之前那个事务的取消。但是这样的事务取消会导致商品秒杀个数的减少(最后会剩下几个商品未秒杀)。

以上的理解有问题吗,请老师指点一下。


正在回答

登陆购买课程后可参与讨论,去登陆

1回答

同学,你好。

第一个问题:with ThreadPoolExecutor(max_workers=10) as executor中的10表示线程池中连接数的最大量,也就是说某一时刻只有10个线程随时会被解释器调度执行,剩余的线程必须等这10个线程中执行完毕的部分将对应的线程执行状态赋予自身才可以进入随时被解释器调度执行状态,而循环中的500表示500人参与对商品的秒杀活动。

问题二中你的理解大部分是正确的,但是当其他事务修改了watch的数据后,本事务因为未能正常execute,所以事务中关于修改秒杀商品数量的操作不会被提交执行,因此也不会造成秒杀商品数量的减少。

如果我的回答解决了您的疑惑,请采纳!祝~学习愉快~

问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师