我正在尝试创建一个简单的机器人,它可以在一段时间后回显您在私信中发送的消息。以下是定时器中的命令及其调用的函数:
@bot.command()
async def reminder(ctx: commands.Context, message: str) -> None:
print("scheduling reminder")
event = {
"message": message,
"timer": Timer(5.0, send_rem, args=[ctx.author, message])
}
user_events[str(ctx.author.id)] = event
event["timer"].start()
print("scheduling reminder")
async def send_rem(author, message):
print("sending reminder")
DM_CHNL = await author.create_dm() if (author.dm_channel is None) else author.dm_channel
if DM_CHNL != None:
await DM_CHNL.send(message)
但是,当我运行机器人并使用提醒命令时,计时器到期后出现此错误:
C:\Users\xxxxx\AppData\Local\Programs\Python\Python313\Lib\threading.py:1342: RuntimeWarning: coroutine 'send_rem' was never awaited
self.function(*self.args, **self.kwargs)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
我假设问题是因为
send_rem
函数是异步的,但我无法阻止它,因为创建和发送消息都是异步的,而且我不知道如何使用asyncio(如果有的话)来处理这个问题。我尝试提供 asyncio.run 作为计时器的回调("timer": Timer(10.0, asyncio.run, args=[send_rem, [ctx.author, message]])
),但 Python 似乎不允许我为函数内的函数指定参数。我该如何处理?
将
threads
与 asyncio
结合使用总是很棘手,应该避免。使用asyncio
中的协程和任务可以完美满足您创建可取消警报的需求。
import asyncio
import discord
from discord.ext import commands
@bot.command()
async def reminder(ctx: commands.Context, message: str) -> None:
print("scheduling reminder")
# we create a coroutine and don't use await
# this way the coroutine will not be inserted into the event loop
coroutine = send_rem(ctx.author, message, 5)
# let's insert the coroutine into the event loop
# and get a task object that can be canceled using `task.cancel()`
# it will run in the background
task = asyncio.create_task(coroutine)
event = {"message": message, "task": task}
user_events[str(ctx.author.id)] = event
print("scheduling reminder")
async def send_rem(author: discord.User, message: str, wait_seconds: float):
# wait asynchronously (does not block the loop) until the reminder time
await asyncio.sleep(wait_seconds)
print("sending reminder")
dm_channel = author.dm_channel or await author.create_dm()
await dm_channel.send(message)