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

Python多线程环境下Telegram Bot异步API适配问题求助

多线程环境下适配python-telegram-bot v20+异步API的解决方案

问题核心

python-telegram-bot从v8升级到v20+后,所有Bot操作(如send_message)均改为异步协程方法。你的代码中queuehandler运行在独立同步线程中,直接调用异步方法会触发错误——该线程未运行asyncio事件循环,且跨线程调用异步协程需要特殊处理逻辑。

解决方案:跨线程安全调用异步协程

使用asyncio.run_coroutine_threadsafe方法,在同步线程中向Bot所在线程的事件循环提交异步协程,实现安全调用。

修改后的完整代码

import threading
import logging
import asyncio
import time
from telegram import ForceReply, Update
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters

# 替换为你的实际配置
TOKEN = "你的Bot Token"
MSG_ID = "目标聊天ID"

class TelegramBotHandler():
    def __init__(self):
        self.application = Application.builder().token(TOKEN).build()
        self.application.add_handler(CommandHandler("help", self.help_command))
        self.bot_loop = None  # 保存Bot运行的事件循环引用

    def runPolling(self):
        self.application.run_polling(allowed_updates=Update.ALL_TYPES)
        # run_polling启动后,application会自动绑定事件循环,后续可直接读取
        self.bot_loop = self.application.loop

    async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
        await update.message.reply_text("Help!")

    def queuehandler(self):
        while True:
            time.sleep(60)
            # 等待Bot事件循环初始化完成
            if not self.bot_loop:
                self.bot_loop = self.application.loop
                if not self.bot_loop:
                    time.sleep(1)
                    continue
            
            # 跨线程提交异步发送消息的协程
            coro = self.application.bot.send_message(chat_id=MSG_ID, text="Hello World")
            future = asyncio.run_coroutine_threadsafe(coro, self.bot_loop)
            
            # 可选:捕获执行结果或异常
            try:
                result = future.result(timeout=10)
                logging.info(f"消息发送成功,ID:{result.message_id}")
            except Exception as e:
                logging.error(f"消息发送失败:{str(e)}")

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    telebot = TelegramBotHandler()
    
    # 启动Bot线程
    telebotthread = threading.Thread(target=telebot.runPolling, daemon=True)
    telebotthread.start()
    
    # 等待Bot初始化完成
    time.sleep(2)
    
    # 启动队列处理线程
    queuehandlerthread = threading.Thread(target=telebot.queuehandler, daemon=True)
    queuehandlerthread.start()
    
    # 主线程保持存活
    try:
        while True:
            time.sleep(3600)
    except KeyboardInterrupt:
        logging.info("程序退出")

关键要点

  • asyncio.run_coroutine_threadsafe是Python官方提供的跨线程调用异步协程的标准方式,它将协程提交到指定事件循环执行,并返回Future对象用于获取结果或捕获异常。
  • 需确保Bot的事件循环初始化完成后再调用异步方法,可通过主线程短暂等待或队列线程内的循环检查实现。
  • 设置线程为daemon=True,保证主线程退出时子线程自动终止,避免程序无法正常退出。
  • 所有Bot异步方法(如send_photo、edit_message_text等)均需按此方式在同步线程中调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:53:30