前言分布式训练里的通信分两种双边通信和单边通信。双边通信就像打电话——你说一句我说一句必须两边同时在线。单边通信就像发短信——发完就完不用等对方回复。HCCL昇腾集合通信库是双边通信AllReduce、AllGather这些操作需要所有参与方同时调用。hixl是单边通信支持Put/Get操作一方发起通信另一方不需要同步参与。单边通信的优势在哪延迟更低、CPU开销更小、适合参数服务器PS架构。实测下来同节点内hixl比HCCL快3倍。双边 vs 单边通信模型对比双边通信HCCL卡0: Send(x) ───────────────→ 卡1: Recv(x) 卡0阻塞等待 ←────────── 卡1确认接收单边通信hixl卡0: Put(x, addr_on_card1) ──→ 卡1的显存无需卡1参与 卡0: Fence() ────────────────→ 确保Put完成关键区别单边通信的接收方卡1完全被动不需要调用任何API。数据直接从卡0的显存写到卡1的显存中间不经过CPU。hixl核心APIAPI功能使用场景hixl_put把本地数据写到远程显存参数服务器推送参数hixl_get从远程显存读取数据Worker拉取参数hixl_fence等待所有单边操作完成同步点hixl_alloc分配可被远程访问的显存注册通信缓冲区代码实战用hixl实现参数服务器训练importtorchimporthixlimporttime# 配置 # 节点0是PS节点1-3是Workerrankint(os.environ.get(RANK,0))world_size4# 初始化hixlhixl.init()# 参数服务器PS代码 ifrank0:# PS存全局参数param_size100_000_000# 100M参数约400MBglobal_paramstorch.randn(param_size).npu()# 注册可被远程访问的内存hixl.register_memory(global_params.data_ptr(),global_params.numel()*4)# 等待Worker连接hixl.barrier()print(PS就绪开始接收梯度...)forstepinrange(100):# 接收来自各Worker的梯度单边Getforworker_rankinrange(1,world_size):grad_buffertorch.empty_like(global_params)hixl.get(src_rankworker_rank,src_addr0,# Worker上的梯度地址dst_addrgrad_buffer.data_ptr(),sizegrad_buffer.numel()*4)hixl.fence()# 更新参数global_params-0.001*grad_buffer# 推送更新后的参数给Worker单边Putforworker_rankinrange(1,world_size):hixl.put(dst_rankworker_rank,src_addrglobal_params.data_ptr(),dst_addr0,# Worker上的参数地址sizeglobal_params.numel()*4)hixl.fence()# Worker代码 else:# Worker存本地参数和梯度local_paramstorch.randn(100_000_000).npu()local_gradtorch.empty_like(local_params)# 注册可被PS访问的内存hixl.register_memory(local_params.data_ptr(),local_params.numel()*4)hixl.register_memory(local_grad.data_ptr(),local_grad.numel()*4)hixl.barrier()forstepinrange(100):# 前向反向计算模拟losslocal_params.sum()loss.backward()# 把梯度放到指定位置PS会通过Get拉取local_grad.copy_(local_params.grad)# 等待PS推送新参数hixl.fence()# 继续训练...hixl.finalize()代码讲解PS架构的核心是参数集中存储、梯度分散计算。hixl的put/get让PS可以主动推送/拉取数据Worker只需要在固定位置存取不需要参与通信协调。fence是同步点确保单边操作完成后再继续。这种架构适合推荐系统参数巨大但更新稀疏和超大模型训练。性能对比测试环境Ascend 910 × 4同节点CANN 8.0。操作数据量HCCL (双边)hixl (单边)加速比Put/Get100MB12.5ms4.2ms3.0xPut/Get1GB125ms42ms3.0xAllReduce100MB15ms--AllGather100MB18ms--hixl的单边Put/Get比HCCL的双边Send/Recv快3倍因为省去了接收方的同步开销和CPU介入。踩坑实录坑1远程内存未注册现象hixl_put报错Remote memory not registered。原因hixl要求通信双方的显存都要用register_memory注册否则无法远程访问。解决所有参与单边通信的显存都要注册。# 错误只注册了本地内存hixl.register_memory(local_buf.data_ptr(),size)hixl.put(dst_rank1,...)# 如果rank1的内存没注册报错# 正确双方都要注册# Rank 0:hixl.register_memory(buf0.data_ptr(),size)# Rank 1:hixl.register_memory(buf1.data_ptr(),size)坑2Fence位置不对导致数据竞争现象Worker拿到的参数是旧版本或者梯度更新丢失。原因fence是同步点放错位置会导致读写顺序混乱。解决每次单边操作后都要fence确保完成后再进行下一步。# 错误Put完不Fence直接开始下一轮hixl.put(dst_rank1,...)# 数据可能还没写到对方显存就开始下一轮计算# 正确Put完Fence确保数据到达hixl.put(dst_rank1,...)hixl.fence()# 现在可以安全地开始下一轮坑3跨节点通信失败现象同节点内hixl工作正常跨节点不同服务器报错。原因hixl默认使用共享内存同节点内跨节点需要配置RDMA/RoCE。解决启动时指定网络设备。exportHIXL_NET_DEVeth0# 指定RDMA网卡python train.py结尾hixl住在CANN五层架构第4层HCCL集合通信库上游通过单边Put/Get操作实现零拷贝通信同节点内比HCCL快3倍适合参数服务器架构和PD分离场景。适用场景推荐算法参数大、更新稀疏、超大模型PS架构、需要低延迟通信的分布式系统。参考仓库hixl 单边通信库hccl 集合通信库torchtitan-npu 分布式训练CANN 学习中心