使用uasyncio实现两个并发无限循环的技术求助
解决MicroPython uasyncio下的闪烁控制与UDP数据获取问题
我编写了一个程序,用于获取家用气象站传输的UDP数据,其中包含名为“rain_accum”的参数,表示过去一分钟的总降雨量。当“rain_accum”>0时,我希望灯光闪烁;当“rain_accum”==0时,灯光停止闪烁。
作为Python新手,我对MicroPython的uasyncio不太熟悉,折腾3天后虽接近实现,但存在严重的时序问题:闪烁延迟高,且UDP消息丢失。以下是精简后的基础代码,寻求指导:
import uasyncio async def blink(): while True: print("Here 1") # 实际代码中对应点亮灯光 await uasyncio.sleep(1) print("Here 2") # 实际代码中对应熄灭灯光 await uasyncio.sleep(1) async def getData(): while True: print("Getting data") # 实际代码中对应接收UDP数据并解析rain_accum if True: # 实际代码中替换为 rain_accum > 0 的判断 await blink() print("Next loop") await uasyncio.sleep(5) try: uasyncio.run(getData()) except KeyboardInterrupt: print("Quitting")
核心问题分析
你的代码关键问题是在getData协程中直接await blink()——blink是无限循环的协程,一旦调用await blink(),getData会被彻底阻塞在这一行,无法继续执行后续的循环逻辑,既无法定期获取UDP数据导致消息丢失,也会让blink完全抢占运行时间,造成时序混乱。
修正后的代码
import uasyncio # 维护闪烁任务的引用,用于控制启动/停止 blink_task = None async def blink(): while True: print("灯光点亮") await uasyncio.sleep(1) print("灯光熄灭") await uasyncio.sleep(1) async def getData(): global blink_task while True: # 模拟获取UDP数据并解析rain_accum,实际替换为UDP接收逻辑 # 示例用随机值模拟降雨状态 import random rain_accum = random.randint(0, 1) print(f"获取到rain_accum: {rain_accum}") if rain_accum > 0: # 闪烁任务未运行时启动它 if blink_task is None or blink_task.done(): blink_task = uasyncio.create_task(blink()) print("启动闪烁任务") else: # 闪烁任务运行中时取消它 if blink_task is not None and not blink_task.done(): blink_task.cancel() blink_task = None print("停止闪烁任务") print("进入下一轮数据获取") await uasyncio.sleep(5) # 实际根据UDP数据频率调整间隔 try: uasyncio.run(getData()) except KeyboardInterrupt: # 退出前清理任务 if blink_task is not None and not blink_task.done(): blink_task.cancel() print("程序退出")
关键优化点
- 并发任务管理:通过
uasyncio.create_task()创建blink的独立任务,让getData和blink可以同时执行,避免互相阻塞。 - 任务状态控制:用全局变量
blink_task跟踪闪烁任务的运行状态,根据rain_accum的值动态启动或取消任务,实现闪烁逻辑的精准控制。 - UDP数据独立性:保持getData循环独立执行,确保能定期接收UDP数据,从根源避免消息丢失问题。
内容的提问来源于stack exchange,提问作者MABeatty1978
相关产品推荐
相关产品推荐

