asyncio中While循环与sleep阻塞协程问题求助
解决Asyncio命令行输入与多周期性任务并行问题
核心是把同步的命令行输入和异步周期性任务拆成独立任务,用asyncio事件循环调度并行执行,同时用任务集合管理多周期性任务。以下是可直接运行的简洁实现:
import asyncio # 存储所有周期性任务的集合,方便跟踪/取消 periodic_tasks = set() async def periodic_task(task_id, interval=2): """单个周期性任务示例,可根据BLE需求替换逻辑""" try: while True: print(f"周期性任务 {task_id} 执行中...") # 这里替换成你的BLE操作,比如 bleak 的设备通信逻辑 await asyncio.sleep(interval) except asyncio.CancelledError: print(f"周期性任务 {task_id} 已终止") async def handle_user_input(): """处理命令行输入,同步input用to_thread避免阻塞事件循环""" task_count = 0 while True: # 把同步的input放到线程里,不阻塞asyncio事件循环 cmd = await asyncio.to_thread(input, "输入命令(0=启动新周期任务,q=退出):") if cmd == "0": task_count += 1 # 创建新的周期性任务并加入集合 task = asyncio.create_task(periodic_task(task_count)) periodic_tasks.add(task) # 任务结束后自动从集合移除 task.add_done_callback(periodic_tasks.discard) print(f"已启动周期性任务 {task_count}") elif cmd.lower() == "q": # 取消所有周期性任务 for task in periodic_tasks: task.cancel() await asyncio.gather(*periodic_tasks, return_exceptions=True) print("所有任务已终止,退出程序") break else: print("未知命令,请输入0或q") async def main(): # 启动命令输入处理任务,事件循环会自动调度它和周期性任务并行 await handle_user_input() if __name__ == "__main__": asyncio.run(main())
关键细节说明
- 同步输入的异步处理:
asyncio.to_thread把阻塞的input()放到单独线程,不会占用asyncio事件循环,保证周期性任务能正常执行。 - 多任务管理:用
set存储周期性任务,任务完成/取消时自动移除,避免内存泄漏。 - 任务并行性:每个
periodic_task用asyncio.create_task启动后,会被事件循环调度独立执行,多个周期任务之间、任务与输入处理之间互不阻塞。 - BLE适配:把
periodic_task里的打印逻辑替换成你的bleak操作(比如连接设备、发送数据、读取特征值)即可,注意bleak的API本身就是异步的,直接await调用就行。
扩展建议
- 如果需要给周期性任务传不同参数(比如不同BLE设备、不同间隔),可以在启动时修改
periodic_task的参数。 - 可以添加其他命令(比如指定任务ID终止单个任务),只需遍历
periodic_tasks找到对应任务调用cancel()即可。
内容的提问来源于stack exchange,提问作者Tsaim
相关产品推荐
相关产品推荐

