discord.py运行长耗时搜索函数阻塞机器人、运行中掉线该如何解决?
问题根源
你的searchTask虽然被定义为异步函数,但内部的文件遍历、读写操作全是同步阻塞逻辑。discord.py依赖的asyncio事件循环是单线程运行的,同步阻塞逻辑会占住整个事件循环线程,导致Discord要求的心跳包无法按时发送,机器人就会被平台判定为离线,同时后续的所有命令、事件也都无法被处理,只能等当前的阻塞逻辑跑完才能继续执行,这就是你遇到的两个问题的核心原因。
可行解决思路
- 把搜索逻辑剥离为独立的同步函数,用
asyncio.run_in_executor扔到线程池运行,避免阻塞事件循环
你可以把原本写在searchTask里的文件遍历、写结果文件的逻辑抽成普通同步函数,示例调整如下:
import asyncio import os # 抽离出来的同步搜索函数 def do_search(self, name, surname): found = False # 注意修改output文件名,用唯一标识避免多个搜索任务同时写同一个文件导致内容混乱 output_path = f"{CURRENT_DIR}/out_{name}_{surname}_{int(time.time())}.txt" with open(output_path, "w") as fwrite: flist = os.listdir(f"{CURRENT_DIR}/datab") for x in flist: with open(f"{CURRENT_DIR}/datab/{x}", "rb") as f: for line in f: # 你原本的搜索匹配逻辑 ... return found, output_path async def searchTask(self, ctx, *args): found = False # 修正你原有代码里lower()后面多打的点的笔误 name = args[0].lower() surname = args[1].lower() await ctx.send("Searching data...") loop = asyncio.get_event_loop() # 将同步搜索逻辑提交到线程池执行,事件循环不会被阻塞 found, output_path = await loop.run_in_executor(None, self.do_search, name, surname) if found: await ctx.send("Done! Here's the result:") await ctx.send(file=discord.File(output_path)) # 用完可以删掉临时文件避免占磁盘 os.remove(output_path) else: await ctx.send("Can't find data") os.remove(output_path)
- 移除多余的
create_task调用,discord.py的命令默认会异步调度,直接await即可,调整命令定义:
def main(self): @self.client.command() async def fsearch(ctx, *args): await self.searchTask(ctx, *args)
- 可选优化:提前为所有待搜索文件构建索引,将需要匹配的字段存储到本地SQLite等数据库中,后续搜索直接查询索引即可,无需每次遍历4GB文件,可将单次搜索耗时从10分钟压缩到毫秒级,从根源解决耗时问题。
- 注意原有代码中
with open上下文管理器会自动关闭文件,你写的手动fwrite.close()是多余的,可以直接删除。
内容的提问来源于stack exchange,提问作者SAL
相关产品推荐
相关产品推荐

