如何在asyncio应用中正确使用Python zeroconf?
解决asyncio环境下Python zeroconf的RuntimeError问题
在asyncio应用中使用zeroconf时,原代码里的同步回调函数调用zeroconf.get_service_info()触发了以下错误:
RuntimeError: Use AsyncServiceInfo.async_request from the event loop
原代码示例:
import asyncio from zeroconf import Zeroconf, ServiceStateChange from zeroconf.asyncio import AsyncServiceBrowser def on_service_state_change(zeroconf, service_type, name, state_change): if state_change == ServiceStateChange.Added: info = zeroconf.get_service_info(service_type, name) print(info) async def browse_services(): zeroconf = Zeroconf() service_type = "_http._tcp.local." browser = AsyncServiceBrowser(zeroconf, service_type, handlers=[on_service_state_change]) try: await asyncio.Event().wait() finally: zeroconf.close() if __name__ == "__main__": asyncio.run(browse_services())
正确实现方式
核心问题是异步环境下不能使用zeroconf的同步API,同时回调函数需要适配异步逻辑。修正后的实现如下:
- 使用
AsyncZeroconf替代同步的Zeroconf,适配asyncio事件循环 - 将回调函数改为异步函数,内部使用异步API获取服务信息
- 借助
async with自动管理AsyncZeroconf的资源释放
完整修正代码:
import asyncio from zeroconf import ServiceStateChange from zeroconf.asyncio import AsyncServiceBrowser, AsyncZeroconf async def handle_service_change(zeroconf: AsyncZeroconf, service_type, name, state_change): if state_change == ServiceStateChange.Added: # 使用异步API获取服务信息 info = await zeroconf.async_get_service_info(service_type, name) print(f"发现服务:{info}") async def browse_services(): # 用AsyncZeroconf替代同步Zeroconf,配合async with自动释放资源 async with AsyncZeroconf() as zeroconf: service_type = "_http._tcp.local." # 传入异步回调函数,zeroconf会自动在事件循环中调度执行 browser = AsyncServiceBrowser(zeroconf, service_type, handlers=[handle_service_change]) # 保持事件循环持续运行 await asyncio.Event().wait() if __name__ == "__main__": asyncio.run(browse_services())
关键修改说明
- AsyncZeroconf:异步版本的核心实例,提供所有异步操作API,避免同步API在事件循环中引发阻塞或错误
- 异步回调:zeroconf的异步浏览器支持接收异步回调函数,会自动将其包装为asyncio任务调度执行,无需手动调用
asyncio.create_task - 资源管理:
async with语法自动处理AsyncZeroconf的初始化和关闭,替代手动调用close()的繁琐操作
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

