首页 > 解决方案 > 如何在并发运行的函数中一次执行部分代码?

问题描述

所以,让我简要介绍一下我想要实现的目标。我有一个名为 的命令apply,只要有人输入该命令,apply 函数就会开始执行。现在,apply 函数有一部分代码我想同时执行,以防许多用户同时触发该命令,并且有一个异步函数调用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. 如果没有,则注册用户并通过增加当前编号来更新数据库。注册人数 1 与await db.execute_query('UPDATE Data SET Total_Reg = Total_Reg + 1 WHERE rowid = 1')

例如,如果有 2 个用户同时申请注册,那么应该先注册一个,然后再注册另一个,并且reg_no他们都应该是唯一的。

就是这样了。我怎样才能实现这个功能?我应该使用队列吗?或者sqlite中是否有任何功能可以首先获取当前的reg。然后将值增加1,如果它小于max_reg并且所有这些都在一个查询中?

谢谢!

标签: pythonsqlsqlitediscord.py

解决方案


好吧,可能存在一个 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是应该检查并发性的地方,公会意味着在一个公会中,如果你希望它是全局使用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)

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

参考:


推荐阅读