如何在并发运行的函数中一次执行一部分代码



所以,让我简要介绍一下我试图实现的目标。我有一个名为apply的命令,只要有人输入该命令,应用函数就会开始执行。现在,application函数有一些代码部分,我想同时执行,以防许多用户同时触发该命令,还有一个名为register的异步函数,我想一次执行一次。以下是代码的一瞥:

@client.command()
async def apply(ctx):
#Stuff I want to be run concurrently
await register(ctx.author)
async def register(user):
# I've an another python file 'db.py' for accessing the database 
data = await db.execute_query('SELECT Total_Reg from Data WHERE rowid = 1')
total = data[0][0] # Getting the total registrations value and storing it in total variable     
if total >= max_reg: # If total reg. are more or equal to max value then close the reg.
print("Registrations are closed!")
return
# Otherwise if registrations are open then increase the value of total reg by 1
# And register the user with unique registration number [reg_no] allotted to him
await db.execute_query('UPDATE Data SET Total_Reg = Total_Reg + 1 WHERE rowid = 1')
reg_no = total + 1
registrations[reg_no] = user
await close_registration() 
"""Also, in case of Queue or execution of this function once at a time, I 
want this function to continue executing the code and shouldn't wait for 
this line of code particularly, i.e await close_registration() should 
keep on executing in background without blocking the current execution of 
this function. So should I use asyncio.ensure_future(close_registration()) 
instead of await or what?"""

我希望你知道我在这里要做什么。现在,让我们来谈谈我的疑问。一旦有人输入apply命令,apply功能就会被discord触发,因此可能存在data = await db.execute_query('SELECT Total_Reg from Data WHERE rowid = 1')可以同时执行多次的情况,这将导致返回当时相同数量的注册,并将其存储在所有注册的总变量中。

我知道,当已经有连接更新或访问数据库时,sqlite会锁定数据库,但一旦执行了一个查询,另一个查询就会在执行await db.execute_query('UPDATE Data SET Total_Reg = Total_Reg + 1 WHERE rowid = 1')增量查询之前开始执行。

我想要的基本上是

这应该是订单:

  1. 获取data = await db.execute_query('SELECT Total_Reg from Data WHERE rowid = 1')的当前注册数
  2. 检查注册是否已满
  3. 如果没有,则注册用户并通过await db.execute_query('UPDATE Data SET Total_Reg = Total_Reg + 1 WHERE rowid = 1')将当前注册数量增加1来更新数据库

例如,如果两个用户同时申请注册,则其中一个用户应首先注册,然后仅注册另一个用户,并且这两个用户的reg_no应是唯一的。

就是这样。我该如何实现这个功能?我应该使用队列吗?或者,sqlite中是否有任何功能可以首先获取当前reg,然后在值小于max_reg的情况下将其增加1,并且仅在一个查询中完成所有这些操作?

谢谢!

可能存在SQL解决方案,但您可以在discord.py 的帮助下继续进行此操作

@commands.max_concurrency(1, commands.BucketType.guild, True)
@commands.command() or #@bot.command() depends on what you are using
async def apply(ctx):
#command here

@commands.max_concurrency(number, bucket_type, wait)允许您控制命令的并发性
number是它可以同时使用的最大次数
bucket_type是应该检查并发性的地方,guild意味着在单个guild中,如果您希望它是全局的,请使用commands.BucketType.default
wait是在有人使用该命令而不应该运行该命令时应该执行的操作。如果我们将其设置为true,它将等待命令完成运行,如果wait为false,它将引发一个错误,该错误可以用错误处理程序捕获。

如果你只想同时执行一次函数,

@commands.command(hidden=True)
@commands.max_concurrency(1, commands.BucketType.guild, True)
async def register(ctx, args):
#do stuff

然而,人们将可以使用注册。

@commands.command()
async def apply(args):
ctx.command = bot.get_command('register')
await bot.invoke(ctx)

非常混乱的代码,但应该可以工作。

参考文献:

  • 最大货币
  • BucketType

最新更新