discord.py定时任务启动报错:无运行事件循环与协程未等待问题
Discord机器人任务启动错误分析与修复
错误回溯信息
Traceback (most recent call last): File "bot.py", line 55, in <module> send_cal.start() File "python3.8/site-packages/discord/ext/tasks/__init__.py", line 398, in start self._task = asyncio.create_task(self._loop(*args, **kwargs)) File "/usr/local/Cellar/python@3.8/3.8.16/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/tasks.py", line 381, in create_task loop = events.get_running_loop() RuntimeError: no running event loop sys:1: RuntimeWarning: coroutine 'Loop._loop' was never awaited
问题代码
@tasks.loop(seconds=20.0) async def send_cal(): message_channel = bot.get_channel(target_channel_id) print(f"Got channel {message_channel}") df = await someApi() df = df.drop(['stuff'], axis=1) csv = df.to_csv(header=False, index=False) res = csv.replace(',', ' ----> ') if (len(res)) >= 2000: await message.channel.send('result over 2000 chars') await message.channel.send(res) @send_cal.before_loop async def before(): await client.wait_until_ready() print("Finished waiting") send_cal.start() client.run('mytoken')
问题原因
- 事件循环未启动时调用任务启动:
send_cal.start()需要依赖已运行的asyncio事件循环创建任务,但你在client.run()之前调用了它——client.run()才是启动Discord机器人事件循环的入口,此时循环尚未初始化,直接触发RuntimeError,进而导致协程未被等待的警告。 - 实例混用:代码中同时使用
bot和client两个不同的机器人实例,before_loop等待client就绪,但任务中调用bot.get_channel,实例不统一导致逻辑混乱,无法正确触发任务等待逻辑。 - 变量未定义:任务中使用了未声明的
message变量,应该替换为前面获取的message_channel,否则后续运行会抛出NameError。
修复方案
方案1:统一实例并保持start()调用顺序
修改代码统一使用一个机器人实例,确保before_loop等待的是同一个实例的就绪状态:
import discord from discord.ext import tasks, commands # 正确实例化机器人(根据需求选择Client或Bot) bot = commands.Bot(command_prefix="!", intents=discord.Intents.all()) # 需开启对应intents target_channel_id = 123456789 # 替换为你的目标频道ID @tasks.loop(seconds=20.0) async def send_cal(): message_channel = bot.get_channel(target_channel_id) print(f"Got channel {message_channel}") df = await someApi() df = df.drop(['stuff'], axis=1) csv = df.to_csv(header=False, index=False) res = csv.replace(',', ' ----> ') if len(res) >= 2000: await message_channel.send('result over 2000 chars') await message_channel.send(res) @send_cal.before_loop async def before(): await bot.wait_until_ready() # 统一使用bot实例 print("Finished waiting") # 先启动任务(before_loop会自动等待事件循环和机器人就绪) send_cal.start() # 启动机器人,触发事件循环 bot.run('mytoken')
方案2:在on_ready事件中启动任务
如果担心start()调用时机问题,可把任务启动放在机器人就绪事件中,确保事件循环已运行:
import discord from discord.ext import tasks, commands bot = commands.Bot(command_prefix="!", intents=discord.Intents.all()) target_channel_id = 123456789 @tasks.loop(seconds=20.0) async def send_cal(): message_channel = bot.get_channel(target_channel_id) print(f"Got channel {message_channel}") df = await someApi() df = df.drop(['stuff'], axis=1) csv = df.to_csv(header=False, index=False) res = csv.replace(',', ' ----> ') if len(res) >= 2000: await message_channel.send('result over 2000 chars') await message_channel.send(res) @bot.event async def on_ready(): print(f"Logged in as {bot.user}") send_cal.start() # 事件循环已启动,可安全调用start() bot.run('mytoken')
关键说明
- Discord.py的
tasks.loop依赖asyncio事件循环,必须在循环启动后调用start(),或通过before_loop中的wait_until_ready()自动等待循环就绪。 - 机器人实例必须保持统一,避免
bot和client混用导致的状态不一致问题。
内容的提问来源于stack exchange,提问作者sf8193
相关产品推荐
相关产品推荐

