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

Discord.py Cogs/Tasks API疑问:为何__init__中启动的任务需手动启动?

Discord机器人定时任务在Cog初始化中无法启动的原因分析

问题描述

我在开发Discord机器人时尝试搭建定时任务功能,为排除外部变量干扰选择了定时循环任务。根据查阅的示例和文档,在Cog的__init__方法中调用self.printer.start()应该能启动任务,但实际运行时必须在bot的on_ready事件中手动启动任务才能正常运行,想知道这一现象的原因。

相关代码

MyCog.py

from discord.ext import commands, tasks
from times import times

class MyCog(commands.Cog):
    def __init__(self,bot):
        print("cog added")
        self.bot = bot
        bot.printer = self.printer
        self.index = 0
        self.printer.start()
        print("end init")

    def cog_unload(self):
        self.printer.cancel()

    @tasks.loop(seconds=5.0)
    async def printer(self):
        print(self.index)
        self.index += 1

async def setup(bot):
    await bot.add_cog(MyCog(bot))

test.py

import datetime
import discord
from discord.ext import commands, tasks
import asyncio
from TOKEN import TOKEN
from MyCog import MyCog
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
    print(f'Logged in as {bot.user.name}')
    if not bot.printer.is_running():
        bot.printer.start()
    #bot.MyCog.start()

async def main():
    await bot.add_cog(MyCog(bot=bot))

if __name__ == "__main__":
    asyncio.run(main())
    bot.run(TOKEN)

运行环境:Python 3.10.4,Windows 10

原因分析

  • 事件循环未初始化:discord.py的定时任务启动依赖bot内部的事件循环。在Cog的__init__执行时,bot.run(TOKEN)还未调用,此时bot的核心事件循环尚未启动,调用start()只会将任务标记为待启动状态,无法真正进入循环执行。
  • 独立事件循环冲突:代码中asyncio.run(main())先执行,它会创建一个临时的事件循环来加载Cog,这个循环和后续bot.run()启动的bot专属事件循环完全独立。临时循环执行完add_cog就结束了,任务根本没有机会绑定到正确的bot循环上。而on_ready事件是在bot成功登录、内部循环完全启动后触发的,此时启动任务才能绑定到活跃的循环中。
  • 任务绑定逻辑限制:tasks.loop装饰的任务调用start()时,会自动绑定到当前线程的默认事件循环。在__init__阶段,要么没有活跃的循环,要么是临时的循环,和bot最终运行的循环不匹配,导致任务无法正常触发。

修正建议

方案1:使用Cog的cog_load方法启动任务

修改MyCog.py,将任务启动逻辑移到异步的cog_load方法中,该方法会在Cog加载到已启动的bot事件循环后执行:

from discord.ext import commands, tasks

class MyCog(commands.Cog):
    def __init__(self,bot):
        print("cog added")
        self.bot = bot
        bot.printer = self.printer
        self.index = 0
        print("end init")

    async def cog_load(self):
        self.printer.start()

    def cog_unload(self):
        self.printer.cancel()

    @tasks.loop(seconds=5.0)
    async def printer(self):
        print(self.index)
        self.index += 1

async def setup(bot):
    await bot.add_cog(MyCog(bot))

方案2:修正代码执行顺序

移除asyncio.run(main()),改用bot的扩展加载机制,确保Cog在bot事件循环启动后加载:
修改test.py:

import discord
from discord.ext import commands
from TOKEN import TOKEN

intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='!', intents=intents)

@bot.event
async def on_ready():
    print(f'Logged in as {bot.user.name}')

async def setup_hook():
    await bot.load_extension("MyCog")

bot.setup_hook = setup_hook

if __name__ == "__main__":
    bot.run(TOKEN)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:23:16