You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何异步运行Discord.py机器人与定时消息异步函数?

问题原因与解决方案

错误原因

你碰到的RuntimeError是因为Discord.py的所有异步API操作(比如fetch_user、发送消息)必须在机器人自身的事件循环中执行。你之前用threading把机器人和定时提醒函数放到了两个独立的线程/事件循环里,跨循环调用机器人的异步方法时,aiohttp的超时上下文管理器无法正常工作,就会触发这个错误。

正确实现方式

不需要额外开启线程,直接利用Discord.py基于asyncio的特性,把定时任务作为后台任务加入到机器人的事件循环中即可。以下是完整的可运行代码:

import asyncio
import discord
from discord.ext import commands
from datetime import datetime, timedelta

DISCORD_BOT_TOKEN = "你的机器人令牌"
DISCORD_ADMIN_ID = 你的管理员ID(数字)
TARGET_HOUR = 14  # 下午2点

class MyBot(commands.Bot):
    def __init__(self):
        # 按需调整Intents,确保获取服务器和频道权限
        super().__init__(command_prefix="!", intents=discord.Intents.all())

    async def setup_hook(self):
        # 机器人启动完成后,启动定时提醒后台任务
        self.loop.create_task(self.start_alerts())

    async def start_alerts(self):
        await self.wait_until_ready()  # 等待机器人完全登录、加载服务器信息
        while not self.is_closed():
            now = datetime.now()
            # 计算下一个下午2点的时间
            target_time = now.replace(hour=TARGET_HOUR, minute=0, second=0, microsecond=0)
            if now >= target_time:
                # 如果今天已经过了2点,就设置为明天的2点
                target_time += timedelta(days=1)
            
            # 计算需要等待的秒数,直接等待到目标时间,避免轮询浪费资源
            wait_seconds = (target_time - now).total_seconds()
            await asyncio.sleep(wait_seconds)

            # 遍历所有服务器发送提醒
            for guild in self.guilds:
                # 这里可以替换成你指定的频道ID,比如 guild.get_channel(频道ID)
                channel = guild.text_channels[0] if guild.text_channels else None
                if channel:
                    try:
                        await channel.send("下午2点的定时提醒来了!")
                    except discord.Forbidden:
                        print(f"服务器 {guild.name} 无发送消息权限")

            # 给管理员发送通知
            try:
                admin = await self.fetch_user(DISCORD_ADMIN_ID)
                await admin.send("已完成所有服务器的定时提醒推送!")
            except discord.NotFound:
                print("未找到管理员用户")
            except discord.Forbidden:
                print("无法给管理员发送私信")

if __name__ == "__main__":
    bot = MyBot()
    bot.run(DISCORD_BOT_TOKEN)

关键说明

  1. 共享事件循环:通过self.loop.create_task把定时任务加入机器人的事件循环,和机器人的命令、事件处理共用同一个循环,避免跨线程/循环的API调用错误。
  2. 等待机器人就绪:wait_until_ready()确保机器人完成登录、加载服务器列表后再执行任务,避免调用self.guilds时为空。
  3. 高效等待逻辑:直接计算距离下一个目标时间的秒数并sleep,比每秒轮询更节省资源。

内容的提问来源于stack exchange,提问作者Aman Agarwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:27:06