如何在discord.py 中等待需要异步的 Timer 协程?

问题描述 投票:0回答:1

我正在尝试创建一个简单的机器人,它可以在一段时间后回显您在私信中发送的消息。以下是定时器中的命令及其调用的函数:

@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 似乎不允许我为函数内的函数指定参数。我该如何处理?

python timer discord.py
1个回答
0
投票

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)
© www.soinside.com 2019 - 2024. All rights reserved.