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

多线程环境下Discord Bot添加discord.ui.View触发RuntimeError求助

解决Discord Bot多线程中使用discord.ui.View的事件循环问题

问题根源

你遇到的RuntimeError: no running event loop,是因为discord.ui.View初始化时会调用asyncio.get_running_loop()获取当前线程的asyncio事件循环,但你的YOLO推理线程是普通同步线程,没有运行任何asyncio事件循环,因此触发错误。

解决方案

推荐采用将Discord交互逻辑(View创建+消息发送)移至主事件循环执行的方案,因为discord.py的API并非线程安全,所有与Discord的交互都应当在Bot的主事件循环线程中完成,工作线程仅负责处理阻塞的推理任务。

具体实现步骤

  1. 在Bot启动时保存主事件循环的引用
  2. 工作线程完成YOLO推理后,将创建View和发送消息的逻辑封装为协程,通过asyncio.run_coroutine_threadsafe()提交到主事件循环执行

示例代码:

import asyncio
import threading
import discord
from ultralytics import YOLO

# 全局保存主事件循环引用
main_event_loop = None
model = YOLO("yolov8n.pt")

def start_bot():
    global main_event_loop
    # 获取并保存主事件循环
    main_event_loop = asyncio.get_running_loop()
    # 初始化Discord Bot
    bot = discord.Bot(intents=discord.Intents.all())
    
    @bot.event
    async def on_ready():
        print(f"Logged in as {bot.user}")
    
    @bot.event
    async def on_message(message):
        if message.author.bot:
            return
        # 处理带图片的消息,启动推理线程
        if message.attachments:
            image_attachment = message.attachments[0]
            image_data = await image_attachment.read()
            threading.Thread(target=detect_task, args=(message, image_data)).start()
    
    bot.run("YOUR_BOT_TOKEN")

def detect_task(message, image_data):
    # 执行YOLO推理(阻塞操作,放在线程中)
    results = model(image_data)
    result_content = f"检测到 {len(results)} 个目标"
    
    # 封装Discord交互逻辑为协程
    async def send_result_with_view():
        # 在主事件循环中创建View,此时能获取到运行的事件循环
        view = discord.ui.View()
        view.add_item(discord.ui.Button(label="查看详情", style=discord.ButtonStyle.primary))
        await message.channel.send(result_content, view=view)
    
    # 将协程提交到主事件循环执行
    asyncio.run_coroutine_threadsafe(send_result_with_view(), main_event_loop)

if __name__ == "__main__":
    start_bot()

不推荐的方案(仅作参考)

如果一定要在工作线程中处理View,可以为工作线程单独创建并运行asyncio事件循环,但这种方式可能引发discord.py对象的线程安全问题,增加代码复杂度:

def detect_task(message, image_data):
    results = model(image_data)
    result_content = f"检测到 {len(results)} 个目标"
    
    # 为工作线程创建新的事件循环
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    
    async def send_with_view():
        view = discord.ui.View()
        view.add_item(discord.ui.Button(label="查看详情", style=discord.ButtonStyle.primary))
        # 注意:此方式可能引发discord对象线程安全问题,不推荐
        await message.channel.send(result_content, view=view)
    
    loop.run_until_complete(send_with_view())
    loop.close()

内容的提问来源于stack exchange,提问作者The one word assaulter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:05:00