使用AbstractEventLoop.call_later调用协程的正确处理方法
在asyncio的call_later中处理异步函数的正确方式
你遇到的问题核心是:loop.call_later 期望接收的是同步回调函数,但你传入的是一个async函数——当回调触发时,它只会调用这个async函数并生成一个协程对象,却没有任何代码去等待这个协程完成,所以才会抛出coroutine was never awaited的警告。
要解决这个问题,你需要在同步回调里把异步函数包装成一个任务(Task),交给事件循环去调度执行。下面是两种适用于Python 3.6的可行方案:
方案1:用loop.create_task包装协程
先写一个同步的包装回调,在里面把异步函数转为任务提交给事件循环:
import asyncio async def foo(iv): await asyncio.sleep(1) print(f'done: {iv}') # 同步回调函数,负责把异步函数包装成任务 def trigger_foo(loop, iv): loop.create_task(foo(iv)) loop = asyncio.get_event_loop() # 把包装后的同步函数传给call_later loop.call_later(2, trigger_foo, loop, 10) try: loop.run_forever() finally: # 确保事件循环被正确关闭 loop.close()
方案2:用asyncio.ensure_future(Python 3.6兼容)
和create_task作用类似,ensure_future也可以把协程转为任务,适合Python 3.6及更早版本:
import asyncio async def foo(iv): await asyncio.sleep(1) print(f'done: {iv}') def trigger_foo(loop, iv): asyncio.ensure_future(foo(iv), loop=loop) loop = asyncio.get_event_loop() loop.call_later(2, trigger_foo, loop, 10) try: loop.run_forever() finally: loop.close()
关键说明
async函数被调用时不会立即执行,只会返回一个协程对象,必须通过await或者交给事件循环作为任务执行,才能真正运行。call_later的回调是同步执行的,所以必须通过上述方式把异步逻辑“桥接”到事件循环中。- 记得用
try/finally块确保事件循环在程序结束时被正确关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Nim




