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

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')

问题原因

  1. 事件循环未启动时调用任务启动:send_cal.start()需要依赖已运行的asyncio事件循环创建任务,但你在client.run()之前调用了它——client.run()才是启动Discord机器人事件循环的入口,此时循环尚未初始化,直接触发RuntimeError,进而导致协程未被等待的警告。
  2. 实例混用:代码中同时使用bot和client两个不同的机器人实例,before_loop等待client就绪,但任务中调用bot.get_channel,实例不统一导致逻辑混乱,无法正确触发任务等待逻辑。
  3. 变量未定义:任务中使用了未声明的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

相关产品推荐
方舟 Agent Plan

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

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