Python 使用Sanic和Redis时出现问题
我正在与2名工人一起使用Sanic。我正在尝试让计费系统工作,即计算用户点击API端点的次数。以下是我的代码:Python 使用Sanic和Redis时出现问题,python,api,redis,multiprocessing,sanic,Python,Api,Redis,Multiprocessing,Sanic,我正在与2名工人一起使用Sanic。我正在尝试让计费系统工作,即计算用户点击API端点的次数。以下是我的代码: class User(object): def __init__(self, id, name, age, address, mobile, credits=0): self.id = id self.name = name self.credits = count self.details = {"ag
class User(object):
def __init__(self, id, name, age, address, mobile, credits=0):
self.id = id
self.name = name
self.credits = count
self.details = {"age": age, "address": address, "mobile_number": mobile}
上面的Users类用于生成我使用另一个python脚本上传到Redis的对象,如下所示:
user = User(..., credits = 10)
string_obj = json.dumps(user)
root.set(f"{user.user_id}", string_obj)
from sanic_redis_ext import RedisExtension
app = Sanic("Testing")
app.config.update(
{
"REDIS_HOST": "127.0.0.1",
"REDIS_PORT": 6379,
"REDIS_DATABASE": 0,
"REDIS_SSL": None,
"REDIS_ENCODING": "utf-8",
"REDIS_MIN_SIZE_POOL": 1,
"REDIS_MAX_SIZE_POOL": 10,
})
@app.route("/test", methods=["POST"])
@inject_user()
@protected()
async def foo(request, user):
user.credits -= 1
if user.credits < 0:
user.credits = 0
return sanic.response.text("Credits Exhausted")
result = process(request)
if not result:
user.credits += 1
await app.redis.set(f"{user.user_id}", json.dumps(user))
return sanic.response.text(result)
当我想要保持端点接收的点击次数的计数,并使用用户对象跟踪它并将其上传回Redis时,主要问题就出现了。我的代码如下:
user = User(..., credits = 10)
string_obj = json.dumps(user)
root.set(f"{user.user_id}", string_obj)
from sanic_redis_ext import RedisExtension
app = Sanic("Testing")
app.config.update(
{
"REDIS_HOST": "127.0.0.1",
"REDIS_PORT": 6379,
"REDIS_DATABASE": 0,
"REDIS_SSL": None,
"REDIS_ENCODING": "utf-8",
"REDIS_MIN_SIZE_POOL": 1,
"REDIS_MAX_SIZE_POOL": 10,
})
@app.route("/test", methods=["POST"])
@inject_user()
@protected()
async def foo(request, user):
user.credits -= 1
if user.credits < 0:
user.credits = 0
return sanic.response.text("Credits Exhausted")
result = process(request)
if not result:
user.credits += 1
await app.redis.set(f"{user.user_id}", json.dumps(user))
return sanic.response.text(result)
当我使用JMeter测试API端点时,10个线程充当同一个用户,信用系统似乎不起作用。在这种情况下,当用户从10个信用开始时,他们可能会剩下7或8个(不可预测)信用,而他们应该剩下0个。据我所知,这是由于工作人员没有共享用户对象,也没有更新变量的副本,这导致他们互相覆盖更新。有谁能帮我找到一个解决方法,这样即使同一个用户同时点击端点,他/她也应该得到完美的账单,用户对象应该保存回Redis。问题是,你从Redis读取信用信息,扣除它,然后将它保存回Redis,这不是一个原子过程。这是一个并发问题 我不懂Python,所以我只使用伪代码 第一个设置用户{user\u id}的10个学分
app.redis.set("{user_id}:credits", 10)
然后这个用户进来了
# deduct 1 from the user credits and get the result
int remaining_credits=app.redis.incryBy ("{user_id}:credits",-1)
if(remaining_credits<=0){
return sanic.response.text("Credits Exhausted")} else{
return "sucess" # or some other result}
#从用户积分中扣除1并获得结果
int remaining_credits=app.redis.incryBy(“{user_id}:credits”,-1)
if(剩余)。不确定您使用的是什么Redis驱动程序,但Redis支持递增/递减操作。您应该使用该驱动程序,而不是设置对象。另一种策略是锁定对象。稍后我将发送代码片段。