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

asyncio.gather启动前两个任务,第三个UDP发送任务未执行

问题原因分析

你的第三个任务GcuUdpClient.send_packets()无法执行,核心原因是**PostServer.run_server()中的同步阻塞操作卡死了asyncio事件循环**:

  • HTTPServer.serve_forever()是同步阻塞方法,会持续占用当前线程,不会让出CPU给asyncio事件循环调度其他任务。你在它前面加的await完全无效,因为该方法并非可等待对象(协程/async函数),导致事件循环被彻底阻塞,GcuUdpClient.send_packets()根本没机会被调度执行。
  • 另外GrpcServer.run()虽为async函数,但server.start()是非阻塞启动,函数执行后会立即返回,任务很快结束,但这不是当前主问题的诱因。
修复方案

1. 修复PostServer,避免阻塞事件循环

把同步的HTTPServer放到独立线程中运行,不占用asyncio事件循环:

修改http_server.py中的PostServer.run_server方法:

class PostServer:
    @staticmethod
    async def run_server(server_class=HTTPServer, handler_class=SimpleHTTPRequestHandler, addr=HTTP_SERVER_IP, port=HTTP_PORT_NUMBER):
        server_address = (addr, port)
        print('Http Post server : {0}:{1}'.format(addr, port))
        httpd = server_class(server_address, handler_class)
        
        # 用守护线程运行同步的serve_forever,不阻塞事件循环
        thread = threading.Thread(target=httpd.serve_forever, daemon=True)
        thread.start()
        
        # 让async函数保持运行状态
        await asyncio.Event().wait()

2. 修复GrpcServer.run,让async函数持续运行

当前GrpcServer.run()在server.start()后直接返回,任务会立即结束,需让它持续运行至服务器终止:

修改grpc_server.py中的GrpcServer.run方法:

class GrpcServer:
    @staticmethod
    async def run():
        server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
        # 修正笔误:将OServices()改为OPSStationServices()
        guidance_grpc_service_definitions_pb2_grpc.add_OpRPCServicesServicer_to_server(OPSStationServices(), server)
        server.add_insecure_port('[::]:{0}'.format(GRPC_PORT_NUMBER))
        print('Grpc Server : {0}:{1}'.format('localhost', GRPC_PORT_NUMBER))
        server.start()
        
        # 等待服务器终止,保持async函数运行
        await server.wait_for_termination()

3. 实现GcuUdpClient的循环发送逻辑

原始代码仅发送一次数据包,若要循环异步发送,需添加循环并使用asyncio原生UDP API:

修改gcu_udp_client.py中的send_packets方法:

class GcuUdpClient:
    @staticmethod
    async def send_packets():
        data = get_data_packet()
        # 使用asyncio UDP客户端,避免同步操作阻塞事件循环
        transport, _ = await asyncio.get_event_loop().create_datagram_endpoint(
            lambda: asyncio.DatagramProtocol(),
            remote_addr=server_address
        )
        try:
            while True:
                transport.sendto(data)
                print('sending data packets')
                await asyncio.sleep(5)
        finally:
            transport.close()

4. 验证主函数

修复后的三个任务可通过asyncio.gather正常并行运行:

async def main():
    await asyncio.gather(
        GrpcServer.run(),
        PostServer.run_server(),
        GcuUdpClient.send_packets()
    )

if __name__ == '__main__':
    asyncio.run(main())
额外注意点
  • 原grpc_server.py中add_OpRPCServicesServicer_to_server传入的OServices()是笔误,需修正为导入的OPSStationServices(),否则会触发未定义错误。
  • 同步socket操作虽单次阻塞时间短,但严格遵循异步规范的话,建议使用asyncio提供的网络API,避免意外阻塞事件循环。

内容的提问来源于stack exchange,提问作者liv2hak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:15:46