Discord.py斜杠命令如何用线程处理耗时任务并返回结果?
解决Discord.py耗时斜杠命令的线程与后续消息发送问题
核心问题原因
直接将interaction对象传入线程后,父协程结束时会回收该对象的上下文资源(如HTTP会话绑定、事件循环关联),导致后续调用interaction.followup.send时因对象失效而失败。同时线程内无法直接调用异步方法,必须通过事件调度处理。
推荐解决方案:使用asyncio.to_thread(无需手动管理线程)
这个方法能将同步耗时函数放到线程池执行,既不阻塞机器人的事件循环,又能保持interaction对象的上下文有效性,代码简洁易维护。
修改后的完整代码:
import asyncio # 你的耗时同步函数 def clientFunction(things: str) -> str: # 模拟5分钟耗时操作 import time time.sleep(300) return f"处理完成:{things}" # TEST COMMAND @bot.tree.command(name="test_command", description="Just a test") @app_commands.describe(things = "nice parameter") async def userTestEvent(interaction: discord.Interaction, things: str): await interaction.response.defer() # 将耗时函数提交到线程池执行,不阻塞事件循环 result = await asyncio.to_thread(clientFunction, things) # 正常发送后续结果消息 await interaction.followup.send(f"{interaction.user.mention}, {result}")
备选方案:手动线程+交互Token发送消息
如果必须手动管理线程,不要传递整个interaction对象,而是提取关键信息(交互Token、用户ID),通过Webhook接口发送后续消息,脱离原对象的上下文依赖。
代码示例:
import threading import asyncio from discord import Webhook, AsyncWebhookAdapter # 你的耗时同步函数 def clientFunction(things: str) -> str: import time time.sleep(300) return f"处理完成:{things}" def run_task(things: str, followup_token: str, user_id: int, bot): # 执行耗时任务 result = clientFunction(things) # 将发送消息的异步任务提交到机器人的事件循环 asyncio.run_coroutine_threadsafe( send_followup(bot, followup_token, user_id, result), bot.loop ) async def send_followup(bot, token: str, user_id: int, result: str): # 通过交互Token创建独立Webhook webhook_url = f"https://discord.com/api/webhooks/{bot.application_id}/{token}" async with AsyncWebhookAdapter(bot.session) as adapter: webhook = Webhook.from_url(webhook_url, adapter=adapter) user = bot.get_user(user_id) await webhook.send(f"{user.mention}, {result}") # TEST COMMAND @bot.tree.command(name="test_command", description="Just a test") @app_commands.describe(things = "nice parameter") async def userTestEvent(interaction: discord.Interaction, things: str): await interaction.response.defer() # 启动线程,传递必要参数而非整个interaction对象 thread = threading.Thread( target=run_task, args=(things, interaction.followup.token, interaction.user.id, bot) ) thread.start()
内容的提问来源于stack exchange,提问作者R0SsAN
相关产品推荐
相关产品推荐

