如何让Microdot异步Web API与其他asyncio函数同时运行?
解决Microdot与异步thermostat协程并发运行的问题
问题根源
你遇到的RuntimeWarning: coroutine 'Microdot.start_server' was never awaited警告,核心原因是microdot_asyncio的app.run()是阻塞式启动方法,它会自行创建并运行事件循环,无法在已有的asyncio事件循环中与其他协程兼容。正确的做法是使用app.start_server()协程,让它在共享事件循环中被await,从而实现和run_thermostat()的并发。
修正后的代码
from microdot_asyncio import Microdot import asyncio class Thermostat: def __init__(self): self.current_temp = 0 self.target_temp = 0 async def async_main(self): # 同时启动web服务和thermostat循环 await asyncio.gather( self.start_web_server(), self.run_thermostat(), ) # 改为异步函数,使用start_server协程替代阻塞的run() async def start_web_server(self): await app.start_server(port=5000) # 可根据需求指定端口 async def read_temperature(self): # 模拟读取传感器温度 self.current_temp = 15 def set_target_temp(self, temp): self.target_temp = temp def control_heating(self): if self.current_temp < self.target_temp: print("Starting heating system") else: print("Stopping heating system") async def run_thermostat(self): while True: await self.read_temperature() # 使用self调用类内方法,避免依赖全局实例 self.control_heating() await asyncio.sleep(1) # 初始化Microdot应用 app = Microdot() @app.route('/set_target_temp') def set_target_temp(request): target_temp = int(request.args['temp']) thermostat.set_target_temp(target_temp) return f"Target temperature set to {target_temp}" # 创建thermostat实例 thermostat = Thermostat() # 启动主协程 if __name__ == "__main__": asyncio.run(thermostat.async_main())
关键修改说明
替换
app.run()为app.start_server():app.start_server()是异步协程,需要被await,能和其他协程在同一个事件循环中并发执行;而app.run()会阻塞并独占事件循环,导致其他协程无法正常运行。使用
asyncio.gather()并发执行协程:asyncio.gather()可以将多个协程打包,让它们在事件循环中同时运行,直到所有协程完成(这里两个都是无限循环,会持续运行)。改用
asyncio.run()启动主协程:
这是Python 3.7+推荐的asyncio启动方式,它会自动创建、管理事件循环,避免手动操作循环带来的兼容性问题。类内方法调用改为
self:run_thermostat中使用self.read_temperature()替代全局实例调用,让代码更健壮,消除对全局变量的依赖。
运行验证
启动代码后,你可以:
- 访问
http://localhost:5000/set_target_temp?temp=20设置目标温度 - 控制台会每秒输出加热系统状态,同时web服务可正常响应请求
内容的提问来源于stack exchange,提问作者yaml01H2S04
相关产品推荐
相关产品推荐

