Python Telegram Bot v20异步运行阻塞及EventLoop报错求助
问题:Python Telegram Bot v20 耗时任务阻塞及事件循环绑定错误
问题现象
使用Python Telegram Bot v20开发的机器人执行耗时任务时,会完全停止响应其他用户;尝试通过线程嵌套异步逻辑解决时,出现事件循环绑定错误:
telegram.error.NetworkError: Unknown error in HTTP implementation: RuntimeError('<asyncio.locks.Event object at 0x0000022361E0A920 [unset]> is bound to a different event loop')
最简复现代码
from telegram import Update from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes import time async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: await update.message.reply_text("start") time.sleep(10) # 模拟耗时任务 await update.message.reply_text("finish") app = ApplicationBuilder().token("TOKEN HERE").build() app.add_handler(CommandHandler("start", start)) app.run_polling()
错误原因
- 同步阻塞导致事件循环卡主:
time.sleep()是同步阻塞函数,会占用asyncio的主事件循环,使其无法处理其他用户的请求。 - 线程方案的逻辑错误:手动创建新事件循环并在其中执行Telegram API调用,而
Update、Context等对象绑定在机器人的主事件循环上,跨事件循环操作会触发绑定错误。
有效解决方案
方案1:用asyncio.run_in_executor处理同步耗时任务
将阻塞的同步任务提交到线程池/进程池执行,不占用主事件循环,同时所有Telegram API调用保持在主循环中:
from telegram import Update from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes import time import asyncio from concurrent.futures import ThreadPoolExecutor # 初始化线程池,可根据任务数量调整max_workers thread_pool = ThreadPoolExecutor(max_workers=4) async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: await update.message.reply_text("start") # 将耗时同步任务交给线程池执行 await asyncio.get_event_loop().run_in_executor( thread_pool, time.sleep, # 替换为你的实际耗时函数 10 ) await update.message.reply_text("finish") app = ApplicationBuilder().token("TOKEN HERE").build() app.add_handler(CommandHandler("start", start)) app.run_polling()
方案2:改用异步版本的耗时任务
如果你的耗时任务支持异步改写(比如网络请求用aiohttp,等待用asyncio.sleep),直接使用异步函数即可:
from telegram import Update from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes import asyncio async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: await update.message.reply_text("start") await asyncio.sleep(10) # 异步等待,不阻塞事件循环 await update.message.reply_text("finish") app = ApplicationBuilder().token("TOKEN HERE").build() app.add_handler(CommandHandler("start", start)) app.run_polling()
内容的提问来源于stack exchange,提问作者8harifi
相关产品推荐
相关产品推荐

