python - 如何在并发运行的函数中一次执行部分代码?
问题描述
所以,让我简要介绍一下我想要实现的目标。我有一个名为 的命令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')
增量查询之前自行开始执行。
我想要的基本上是,
这应该是顺序:
- 获取当前注册数
data = await db.execute_query('SELECT Total_Reg from Data WHERE rowid = 1')
- 检查注册是否已满
- 如果没有,则注册用户并通过增加当前编号来更新数据库。注册人数 1 与
await db.execute_query('UPDATE Data SET Total_Reg = Total_Reg + 1 WHERE rowid = 1')
例如,如果有 2 个用户同时申请注册,那么应该先注册一个,然后再注册另一个,并且reg_no
他们都应该是唯一的。
就是这样了。我怎样才能实现这个功能?我应该使用队列吗?或者sqlite中是否有任何功能可以首先获取当前的reg。然后将值增加1,如果它小于max_reg
并且所有这些都在一个查询中?
谢谢!
解决方案
好吧,可能存在一个 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)
非常混乱的代码,但应该可以工作。
参考:
推荐阅读
- java - Spring Boot 注入失败
- pyqt5 - 如何在 QListView 中修改 drop 事件
- python-3.x - 试图从多个 excel 文件中获取 sheet1 并将它们移动到一个工作簿中
- testing - Spectron 可以用于非电子网络应用程序吗?
- python - 硒中的find_elements是否可以设置一定的深度?
- python - Python,将许多具有相似格式的文本文件导入带有格式的excel电子表格
- javascript - Redux/toolkit 在注销时重置所有状态,除了一个
- ruby-on-rails - 在所有请求之前运行的 RSwag RSpec 测试中执行数据库设置部分
- python - 递归/递归跟踪
- swift - 如何从其他视图更改 @State 变量