Python中asyncio跨事件循环与线程传对象报错求助
解决asyncio跨线程事件循环报错
got Future <Future pending> attached to a different loop 你的问题根源在于:
update和context对象绑定在主线程的asyncio事件循环上,你在子线程中新建了独立的事件循环,调用依赖这些对象的reply_text方法时,就会触发跨循环的Future错误。- 在async函数里使用
time.sleep(20)会直接阻塞整个事件循环,违背了异步编程的原则。
最优解决方案:不额外创建线程,直接在原事件循环中启动异步任务
asyncio本身是单线程异步模型,不需要额外开启线程处理后台任务,直接用asyncio.create_task把alert任务提交到原事件循环即可:
import asyncio from telegram import Update from telegram.ext import ContextTypes async def callback_onlyAlert(update: Update, context: ContextTypes.DEFAULT_TYPE): await update.message.reply_text('Ok! \nI will send you a message only when you can withdraw your USDN') # 直接在当前事件循环启动alert异步任务 asyncio.create_task(alert(update, context)) async def alert(update: Update, context: ContextTypes.DEFAULT_TYPE): global block global withdrawal_block while True: await update.message.reply_text("⚠️⚠️ -10 MINUTES! ⚠️⚠️") # 用asyncio.sleep替代time.sleep,避免阻塞事件循环 await asyncio.sleep(20)
若必须使用线程的兼容方案
如果业务场景确实需要用到线程,不要在子线程新建事件循环,而是把主线程的事件循环传入子线程,通过asyncio.run_coroutine_threadsafe在原循环上调度协程:
import asyncio import threading from telegram import Update from telegram.ext import ContextTypes async def callback_onlyAlert(update: Update, context: ContextTypes.DEFAULT_TYPE): await update.message.reply_text('Ok! \nI will send you a message only when you can withdraw your USDN') # 获取当前运行的主线程事件循环 main_loop = asyncio.get_running_loop() # 启动子线程并传入原事件循环 t = threading.Thread(target=middleware_alert, args=(main_loop, update, context,)) t.start() def middleware_alert(main_loop, update: Update, context: ContextTypes.DEFAULT_TYPE): # 在原事件循环上调度alert协程 future = asyncio.run_coroutine_threadsafe(alert(update, context), main_loop) try: # 这里因为alert是无限循环,会一直阻塞子线程,可根据需求调整 future.result() except Exception as e: print(f"任务执行出错: {e}") async def alert(update: Update, context: ContextTypes.DEFAULT_TYPE): global block global withdrawal_block while True: await update.message.reply_text("⚠️⚠️ -10 MINUTES! ⚠️⚠️") await asyncio.sleep(20)
关键注意点
- 永远不要在async函数中使用
time.sleep(),这会阻塞整个事件循环,必须替换为await asyncio.sleep()。 - 与事件循环绑定的对象(比如你的
update、context)不能跨循环使用,所有依赖这些对象的异步操作必须在它们所属的事件循环上执行。
内容的提问来源于stack exchange,提问作者Jacopo Mosconi
相关产品推荐
相关产品推荐

