You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

关键注意点

  1. 永远不要在async函数中使用time.sleep(),这会阻塞整个事件循环,必须替换为await asyncio.sleep()。
  2. 与事件循环绑定的对象(比如你的update、context)不能跨循环使用,所有依赖这些对象的异步操作必须在它们所属的事件循环上执行。

内容的提问来源于stack exchange,提问作者Jacopo Mosconi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 14:05:38