You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:41:42