Pyrogram多线程环境下超时上下文管理器RuntimeError排查与修复
错误原因
你在Pyrogram的异步主线程里直接调用了aiogram的bot.send_message异步方法,但aiogram的Bot实例绑定的是另一个独立线程的事件循环。跨线程直接调用异步方法会导致事件循环上下文不匹配,触发Timeout context manager should be used inside a task错误——异步方法必须在所属的事件循环上下文中执行,跨线程调用会破坏异步任务的上下文规则。
修复方案
方案1:用线程安全队列解耦消息发送逻辑
在aiogram线程中维护一个线程安全队列,所有发送消息的请求先入队,由aiogram自己的事件循环处理发送:
- main.py中初始化队列并启动aiogram线程:
import queue from threading import Thread from aiogram import Bot, Dispatcher import asyncio # 线程安全队列,用于传递消息请求 message_queue = queue.Queue() async def aiogram_runner(): bot = Bot(token="你的aiogram机器人令牌") dp = Dispatcher() # 后台任务:监听队列并处理消息发送 async def process_queue(): while True: chat_id, text = await asyncio.to_thread(message_queue.get) await bot.send_message(chat_id=chat_id, text=text) message_queue.task_done() # 启动队列处理任务 asyncio.create_task(process_queue()) await dp.start_polling(bot) def start_aiogram(): asyncio.run(aiogram_runner()) # 启动aiogram线程 Thread(target=start_aiogram).start()
- trade.py中通过队列发送消息:
from main import message_queue # 替换原bot.send_message调用,改为入队 message_queue.put((目标聊天ID, "要发送的消息内容"))
方案2:用asyncio.run_coroutine_threadsafe跨线程提交任务
直接把aiogram的异步任务提交到它所属的事件循环中执行:
- main.py中保存aiogram的事件循环引用:
import asyncio from threading import Thread from aiogram import Bot, Dispatcher aiogram_event_loop = None aiogram_bot = None async def aiogram_runner(): global aiogram_event_loop, aiogram_bot aiogram_event_loop = asyncio.get_running_loop() aiogram_bot = Bot(token="你的aiogram机器人令牌") dp = Dispatcher() await dp.start_polling(aiogram_bot) def start_aiogram(): asyncio.run(aiogram_runner()) Thread(target=start_aiogram).start()
- trade.py中跨线程调用异步方法:
from main import aiogram_event_loop, aiogram_bot import asyncio def send_aiogram_msg(chat_id, text): # 把异步协程提交到aiogram的事件循环 coro = aiogram_bot.send_message(chat_id=chat_id, text=text) future = asyncio.run_coroutine_threadsafe(coro, aiogram_event_loop) # 可选:等待执行结果并处理异常 try: future.result(timeout=10) except Exception as e: print(f"消息发送失败: {str(e)}") # 调用示例 send_aiogram_msg(目标聊天ID, "测试消息")
关键注意事项
- aiogram的Bot实例必须在自己的线程中初始化,不要跨线程直接共享Bot实例,避免上下文冲突。
- Pyrogram的主线程是异步上下文,所有Pyrogram相关逻辑要在它的事件循环中执行,跨线程调用其他异步框架的方法必须用线程安全的桥接方式(队列或
run_coroutine_threadsafe)。
内容的提问来源于stack exchange,提问作者Dude
相关产品推荐
相关产品推荐

