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

为何基于Webhooks的Python Telegram Bot无法像Long Polling那样并发处理多用户消息?

为什么Aiogram的Webhook模式无法像Long Polling那样并发处理多用户消息?

我用aiogram框架开发Telegram Bot,测试逻辑是接收用户消息后10秒返回回声消息。实际要做的是服务大量用户的电影购买Bot,要求支持多用户消息并发处理,且必须用Webhooks方式接收消息。

下面是两段测试用的Python脚本:

基于Long Polling的Telegram Bot

import asyncio
import logging
from aiogram import Bot, Dispatcher, executor, types
from bot_files.config import *

# Configure logging
logging.basicConfig(level=logging.INFO)

# Initialize bot and dispatcher
bot = Bot(token=bot_token)
dp = Dispatcher(bot)

@dp.message_handler()
async def echo(message: types.Message):
    await asyncio.sleep(10)
    await message.answer(message.text)

if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

基于Webhooks的Telegram Bot

import asyncio
import logging
from aiogram import Bot, Dispatcher, executor, types
from bot_files.config import *

# Configure logging
logging.basicConfig(level=logging.INFO)

# Initialize bot and dispatcher
bot = Bot(token=bot_token)
dp = Dispatcher(bot)

WEBHOOK_HOST = f'https://7417-176-8-60-184.ngrok.io'
WEBHOOK_PATH = f'/webhook/{bot_token}'
WEBHOOK_URL = f'{WEBHOOK_HOST}{WEBHOOK_PATH}'

# webserver settings
WEBAPP_HOST = '0.0.0.0'
WEBAPP_PORT = os.getenv('PORT', default=5000)

async def on_startup(dispatcher):
    await bot.set_webhook(WEBHOOK_URL, drop_pending_updates=True)

async def on_shutdown(dispatcher):
    await bot.delete_webhook()

@dp.message_handler()
async def echo(message: types.Message):
    await asyncio.sleep(10)
    await message.answer(message.text)

if __name__ == '__main__':
    executor.start_webhook(
        dispatcher=dp,
        webhook_path=WEBHOOK_PATH,
        skip_updates=True,
        on_startup=on_startup,
        on_shutdown=on_shutdown,
        host=WEBAPP_HOST,
        port=WEBAPP_PORT
    )

测试发现:Long Polling模式下,两名用户同时发消息时能并发处理,都在10秒内收到回复;但Webhooks模式下消息会线性处理,其中一名用户要等20秒才能收到回复。请问为什么基于Webhooks的Telegram Bot无法像Long Polling那样同时处理多用户消息?


问题原因

默认情况下,aiogram的executor.start_webhook()使用单线程的aiohttp服务器,每个请求会被串行处理——当第一个请求的处理函数(比如你的echo)里有await asyncio.sleep(10)这类耗时异步操作时,服务器会被该请求占用,直到处理完成才会响应下一个请求。

而Long Polling模式的executor.start_polling()内部是通过异步任务拉取和处理消息,每条新消息都会被包装成独立的异步任务交给事件循环并发执行,所以多用户请求能同时处理。

解决方法

要让Webhook模式支持并发,需要修改Web服务器配置,启用多线程/多进程处理请求,同时确保处理逻辑是真正的异步:

1. 启用多线程Web服务器

调用executor.start_webhook()时添加workers参数指定工作线程数,比如设置为4:

if __name__ == '__main__':
    executor.start_webhook(
        dispatcher=dp,
        webhook_path=WEBHOOK_PATH,
        skip_updates=True,
        on_startup=on_startup,
        on_shutdown=on_shutdown,
        host=WEBAPP_HOST,
        port=WEBAPP_PORT,
        workers=4  # 指定工作线程数,实现并发处理
    )

workers参数会让aiohttp启动多个线程,每个线程拥有独立的事件循环,多个请求就能并行处理。

2. 确保处理逻辑异步无阻塞

如果后续的电影购买逻辑包含同步阻塞操作(比如数据库查询、文件IO),要将其包装为异步任务,避免阻塞事件循环。例如:

@dp.message_handler()
async def buy_movie(message: types.Message):
    # 把同步操作放到独立线程执行,不阻塞事件循环
    result = await asyncio.to_thread(sync_db_query, message.text)
    await message.answer(f"购买结果:{result}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:25:12