使用Telethon+Telebot+asyncio时,get_entity()调用致程序冻结
解决Telethon与Telebot异步混用中
get_entity(url)冻结的问题 问题现象
- 同时用Telethon解析频道订阅者列表、Telebot搭建机器人,依赖asyncio实现异步逻辑
- 异步函数执行到
channel = await client.get_entity(url)时,程序直接冻结,无任何异常或警告输出 - 替换代码为
channel = await client.get_input_entity(InputPeerChannelFromMessage('Channel', message.id, message.chat.id))后,程序恢复正常运行 - 单独使用Telethon时,
get_entity("t.me/channellink")可以正常工作
问题根源
Telebot(python-telegram-bot)的异步事件循环与Telethon的网络请求调度逻辑存在兼容性冲突。get_entity(url)需要发起网络请求解析频道实体,但在Telebot的循环上下文里,这个IO操作被阻塞,无法正常完成调度。
可行解决方案
1. 利用消息上下文调用get_input_entity
既然已经验证InputPeerChannelFromMessage可以正常获取实体,直接沿用这种方式:
from telethon.tl.types import InputPeerChannelFromMessage # 在Telebot的消息处理异步函数内 channel = await client.get_input_entity(InputPeerChannelFromMessage('Channel', message.id, message.chat.id))
这种方式直接基于当前消息的上下文获取频道实体,跳过了get_entity(url)需要的额外网络解析步骤,规避了两个库的循环冲突。
2. 给Telethon单独分配事件循环线程
让Telethon和Telebot各自运行在独立的事件循环中,从根源上解决循环干扰问题:
import asyncio from threading import Thread def run_telethon_loop(client): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(client.start()) loop.run_forever() # 启动Telethon的独立线程 telethon_thread = Thread(target=run_telethon_loop, args=(client,), daemon=True) telethon_thread.start() # 在Telebot的处理函数中,跨线程调用Telethon方法 async def handle_bot_message(message): url = "t.me/channellink" coro = client.get_entity(url) # 将协程提交到Telethon的事件循环执行 future = asyncio.run_coroutine_threadsafe(coro, asyncio.get_event_loop()) channel = future.result() # 后续处理订阅者列表的逻辑
3. 改用Bot API直接获取频道信息(需求允许时)
如果仅需要频道的基础信息,可直接通过Telebot调用官方Bot API的getChat方法,完全避开Telethon的实体解析逻辑:
# 在Telebot的消息处理函数内 chat = await bot.get_chat("@channelusername") # chat对象包含频道ID、标题等核心信息,可用于后续逻辑
内容的提问来源于stack exchange,提问作者George Firsanov
相关产品推荐
相关产品推荐

