如何在后台运行asyncio协程?——基于aiogram调度器的实践疑问
解决aiogram协程后台运行不阻塞主线程的问题
我明白你从JS转过来的困惑——JS的事件循环是环境自动管理的,而Python的asyncio需要我们手动掌控事件循环的运行逻辑,这也是你之前各种尝试碰壁的原因。咱们一步步拆解问题,找到符合你需求的方案:
核心误区:Python asyncio的单线程事件循环
首先得明确:Python的asyncio是单线程事件循环模型,所有协程都在同一个线程的事件循环里调度执行。你不能期望像JS那样直接调用协程就让它在“后台”跑——必须把协程交给事件循环管理,同时让事件循环持续运行,还要把你的其他任务也纳入这个循环的调度中。
正确的实现方式
如果你不想用线程,那所有需要并发执行的逻辑都得写成协程,然后让它们在同一个事件循环里被调度。这里有两种简洁的实现方式:
方式1:用asyncio.gather()同时启动多个协程(推荐Python3.7+)
把start_polling和你的自定义任务都放进asyncio.gather(),再用asyncio.run()启动事件循环,这样两个协程会被并发执行:
import asyncio from aiogram import Bot, Dispatcher from aiogram.types import Message # 初始化bot和调度器 API_TOKEN = "你的Telegram Bot Token" bot = Bot(token=API_TOKEN) dp = Dispatcher(bot) # 你的自定义后台任务(必须是协程函数) async def my_custom_task(): while True: print("正在执行主线程的其他任务...") await asyncio.sleep(3) # 关键:必须有await让事件循环切换任务 # aiogram的消息处理器示例 @dp.message_handler(commands=["start"]) async def send_welcome(message: Message): await message.reply("Hello! 我在运行的同时,后台任务也没停~") async def main(): # 同时启动polling和自定义任务 await asyncio.gather( dp.start_polling(), my_custom_task() ) if __name__ == "__main__": asyncio.run(main())
方式2:用create_task提交任务+事件循环run_forever
如果你需要更灵活地控制事件循环(比如手动停止),可以用这种方式:
import asyncio from aiogram import Bot, Dispatcher API_TOKEN = "你的Telegram Bot Token" bot = Bot(token=API_TOKEN) dp = Dispatcher(bot) async def my_custom_task(): while True: print("自定义任务在运行...") await asyncio.sleep(3) if __name__ == "__main__": loop = asyncio.get_event_loop() # 把两个任务都提交到事件循环 loop.create_task(dp.start_polling()) loop.create_task(my_custom_task()) # 启动事件循环(会阻塞直到调用loop.stop()) loop.run_forever()
为什么你之前的尝试失败?
- 直接调用
dp.start_polling():Python会提示“协程从未被等待”,因为协程必须被await或者交给事件循环管理,不能直接执行。 run_until_complete(dp.start_polling()):这个方法会阻塞线程,直到传入的协程执行完毕——但start_polling是无限循环的,所以线程会一直被占用。create_task+run_forever:如果你只提交了start_polling一个任务,那事件循环只会跑这个任务;但如果同时提交多个任务,它们会被并发调度,只是run_forever本身会阻塞线程(这是正常的,因为事件循环需要持续运行才能调度任务)。
关键注意点
- 所有需要并发的逻辑必须写成协程函数,并且里面要有足够的
await语句——这是事件循环切换任务的触发点,否则某个协程会一直占用事件循环,导致其他任务无法执行。 - 如果你需要在同步代码里触发协程操作,那得用
asyncio.run()或者获取当前事件循环来提交任务,但本质还是要在事件循环的上下文里。
内容的提问来源于stack exchange,提问作者horart
相关产品推荐
相关产品推荐

