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

异步pyTelegramBotApi跨线程调用send_message请求超时问题

问题诊断与解决

核心问题

错误根源在于跨线程调用异步方法时的事件循环冲突:

  • Telegram机器人的异步客户端tg_bot运行在主事件循环中(由main函数启动并执行infinity_polling)
  • VK的监听循环是同步阻塞的,运行在单独线程中,你用asyncio.run(tg_bot.send_post(...))会创建一个全新的独立事件循环,这个新循环无法复用主循环中已建立的Telegram连接会话,导致请求超时。

修复方案

1. 保存主事件循环引用

修改启动代码,把主事件循环保存下来,供其他线程调用:

import asyncio
import threading

# 全局保存主事件循环引用
main_loop = None

async def main():
    global main_loop
    main_loop = asyncio.get_running_loop()
    
    vk_thread = threading.Thread(target=run_vk_loop)
    vk_thread.start()

    await tg_bot.init()

if __name__ == "__main__":
    asyncio.run(main())

2. 修改VK循环中的异步调用方式

在VK的监听循环里,不要用asyncio.run,而是用asyncio.run_coroutine_threadsafe把异步任务提交到主事件循环:

import asyncio
import time

def init():
    print("Starting VK Cycle")
    try:
        for event in longpoll.listen():
            print("There's a VK event")
            event_received = False
            while not event_received:
                print("Trying to receive it...")
                try:
                    if event.type == VkBotEventType.WALL_POST_NEW:
                        print("It's a new post on the wall")
                        post = event.object

                        if post.post_type == 'suggest':
                            print("The new post is a suggested post")
                            # 替换asyncio.run,用线程安全的方式提交任务到主循环
                            future = asyncio.run_coroutine_threadsafe(
                                tg_bot.send_post(text=post.text, post_id=post.id),
                                main_loop
                            )
                            # 可选:获取执行结果,避免任务异常无感知
                            try:
                                future.result(timeout=10)
                            except Exception as e:
                                print(f"Send post failed: {e}")

                    event_received = True
                except requests.exceptions.ReadTimeout as e:
                    print("ERROR: ReadTimeout. Waiting for 3 seconds and trying to reconnect")
                    # 用with语句更安全地操作日志文件
                    with open("cogparty.log", "a") as log_file:
                        log_file.write(
                            f"\n\nvkontakte.py init() INNER try-catch error:\n\n{str(e)}\n\nTrying again in 3 seconds...")
                    time.sleep(3)
    except Exception as e:
        print(f"ERROR: {type(e).__name__}::{str(e)}")
        with open("cogparty.log", "a") as log_file:
            log_file.write(f"\n\nvkontakte.py init() OUTER try-catch error:\n\n{str(e)}")

3. 额外优化建议

  • 日志操作统一用with语句,避免文件句柄泄漏
  • 给future.result()设置合理超时,防止VK线程被长时间阻塞
  • 确保my_chat_id、gen_markup()等变量/方法的线程安全性(如果存在状态共享)

为什么之前能运行?

之前偶然正常是因为新创建的事件循环侥幸建立了新的Telegram连接,但这种方式本身不稳定,长时间运行后会因为资源耗尽或连接冲突导致崩溃,这也是现在启动就失败的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 00:35:55