Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/api/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用Sanic和Redis时出现问题_Python_Api_Redis_Multiprocessing_Sanic - Fatal编程技术网

Python 使用Sanic和Redis时出现问题

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

我正在与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 = {"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支持递增/递减操作。您应该使用该驱动程序,而不是设置对象。另一种策略是锁定对象。稍后我将发送代码片段。