Asyncio下PyModbus异步服务器持续运行任务的实现疑问
异步PyModbus服务器与asyncio任务问题解决
问题1:asyncio.run与create_task的差异及程序退出原因
asyncio.run(coro):会自动创建新的事件循环,运行传入的协程直到它完成,最后自动关闭循环。示例里的服务器协程是持续运行的,所以run会一直阻塞,保持程序存活。asyncio.create_task(coro):只是把协程包装成任务,加入当前正在运行的事件循环,但它不会阻塞当前线程。如果你的myFunction是普通函数,调用create_task后函数执行完毕,主线程没有任何代码让事件循环持续运行,程序就会直接退出,任务自然无法持续执行。关于“Task was destroyed but it is pending!”错误:通常是因为你手动获取事件循环后,没有让循环持续运行(比如没调用
loop.run_forever()),或者提前关闭了循环(比如loop.close()),导致已创建的pending任务被强制销毁。正确做法是让循环持续运行,直到所有任务被正常取消或完成。
问题2:实现多个持续运行的任务
1. 改造更新任务为每秒递增
原示例的更新任务只执行一次,需要改成带循环的协程,每秒更新寄存器值:
async def update_server_values(context): while True: # 获取保持寄存器(功能码3),从地址0开始,共10个 holding_regs = context[0].getValues(3, 0, count=10) # 每个寄存器值+1 updated_regs = [val + 1 for val in holding_regs] context[0].setValues(3, 0, updated_regs) await asyncio.sleep(1)
2. 同时运行多个任务
创建一个主协程,在里面启动所有任务,然后用asyncio.gather等待所有任务(如果任务是无限循环,这里会一直阻塞):
async def main(): # 初始化Modbus服务器上下文 store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [0]*100), co=ModbusSequentialDataBlock(0, [0]*100), hr=ModbusSequentialDataBlock(0, [0]*100), ir=ModbusSequentialDataBlock(0, [0]*100) ) context = ModbusServerContext(slaves=store, single=True) # 创建服务器任务 server_task = asyncio.create_task(run_updating_server(context)) # 创建更新值任务 update_task = asyncio.create_task(update_server_values(context)) # 创建锁触发的独立任务 lock = asyncio.Lock() lock_task = asyncio.create_task(lock_triggered_task(lock)) # 等待所有任务完成(无限循环任务会一直阻塞在这里) await asyncio.gather(server_task, update_task, lock_task) # 锁触发任务示例:每秒尝试获取锁,获取到后执行操作 async def lock_triggered_task(lock): while True: async with lock: # 执行需要锁保护的操作 print("锁触发任务执行中...") await asyncio.sleep(0.5) # 模拟操作耗时 await asyncio.sleep(1) if __name__ == "__main__": asyncio.run(main())
关键注意点
- 所有持续运行的任务都要包含
while True循环和await asyncio.sleep(),避免阻塞事件循环。 - 用
asyncio.run(main())启动主协程,它会自动管理事件循环的生命周期,避免手动操作循环带来的错误。 - 多个任务共享资源时,用
asyncio.Lock确保安全访问,避免竞态条件。
内容的提问来源于stack exchange,提问作者sokol07
相关产品推荐
相关产品推荐

