pyasc Matmul 异步取结果接口 async_get_tensor_c 使用指南:从 Iterate 异步计算获取 C 矩阵的正确姿势
2026/9/18 16:58:02 网站建设 项目流程

pyasc Matmul 异步取结果接口 async_get_tensor_c 使用指南:从 Iterate 异步计算获取 C 矩阵的正确姿势

【免费下载链接】pyasc本项目为Python用户提供算子编程接口,支持在昇腾AI处理器上加速计算,接口与Ascend C一一对应并遵守Python原生语法。项目地址: https://gitcode.com/cann/pyasc

导读

本文聚焦 CANN pyasc(为 Python 用户提供、与 Ascend C 一一对应的算子编程接口)中asc.language.adv.Matmul高阶矩阵乘法 API 的异步取结果接口async_get_tensor_c。文章从该接口的签名与语义出发,结合仓库源码与其接替者get_tensor_c,讲清"何时用它、它如何工作、为何官方建议改用get_tensor_c异步模式、以及 MixDualMaster 双主模式下的使用禁区",并给出可直接套用的异步计算完整代码骨架。读完本文,你将能理解 Matmul 迭代计算的同步/异步两条取数路径,并正确迁移到官方推荐的异步写法。

接口速览:签名、原型与语义

async_get_tensor_cMatmul类上用于"获取 Iterate 接口异步计算的结果矩阵"的成员方法,其完整签名定义于仓库的 接口参考文档:

Matmul.async_get_tensor_c(c: LocalTensor) → None
  • 功能:获取 Iterate 接口异步计算的结果矩阵,即把异步模式下由迭代计算产生的 C 矩阵分片取出到用户指定的 LocalTensor。
  • 对应 Ascend C 函数原型
__aicore__ inline void AsyncGetTensorC(const LocalTensor<DstT>& c)
  • 参数说明c—— 结果矩阵,类型为LocalTensor,即存放 C 矩阵分片的目标缓冲区。
  • 约束说明:当使能 MixDualMaster(双主模式)场景时,即模板参数enableMixDualMaster设置为true时,不支持使用该接口。
  • 重要状态提示:文档明确说明"该接口功能已被 GetTensorC 覆盖,建议直接使用 GetTensorC 异步接口",即这是一个已被功能替代、保留兼容的接口,新代码应优先走 Matmul.get_tensor_c 的异步路径。

背景:Matmul 高阶 API 与 Iterate 迭代计算

在 pyasc 中,Matmul是一组与 Ascend C Matmul 高阶 API 一一对应的封装,其计算模型为C = A * B + Bias(见 Matmul 类定义)。使用流程通常为:

  1. MatmulType声明 A、B、C 的位置、格式与数据类型,构造Matmul对象;
  2. 通过asc.adv.register_matmul(pipe, workspace, matmul)完成注册;
  3. matmul.init(tiling)用 tiling 信息初始化;
  4. matmul.set_tensor_a(...)matmul.set_tensor_b(...)等配置输入;
  5. 调用matmul.iterate(...)逐块迭代计算baseM * baseN的 C 矩阵分片;
  6. 通过取结果接口把 C 分片搬运到目标位置;
  7. matmul.end()收尾。

iterate是异步取数的前提:每次调用 Matmul.iterate 会计算出一块baseM * baseN的 C 矩阵,其签名支持sync: bool参数控制同步或异步模式。同步模式下,while mm.iterate() as count:循环内直接取数即可;异步模式下,iterate(sync=False)只发起计算不等待完成,取数侧需要配合 wait/异步取数接口,这正是async_get_tensor_c存在的场景。

源码实现:一个 Op 的薄封装

在仓库中,async_get_tensor_c的实现位于 python/asc/language/adv/matmul.py#L563-L567,是典型的"IR 构建器薄封装"模式:

@require_jit @set_matmul_docstring(api_name="async_get_tensor_c") def async_get_tensor_c(self, c: LocalTensor) -> None: builder = global_builder.get_ir_builder() builder.create_asc_MatmulAsyncGetTensorCOp(self.to_ir(), c.to_ir())
  • @require_jit装饰器表明该方法必须在@asc.jit装饰的 kernel 函数内调用,由 JIT 编译器捕获并翻译为 IR;
  • create_asc_MatmulAsyncGetTensorCOp会在 IR 中创建一个MatmulAsyncGetTensorCOp算子,把Matmul对象句柄与c(LocalTensor)句柄一并传入,后续由编译流水线发射为 Ascend C 代码中的AsyncGetTensorC
  • 其用户可见的文档字符串并非硬编码在 matmul.py 中,而是由 python/asc/language/adv/utils.py#L783-L810 的async_get_tensor_c_docstring()动态生成,并通过set_matmul_docstring注入。这也解释了为什么官方文档与源码注释语义完全一致——它们出自同一处模板,文档生成工具docs/API_docstring_generation_tool_guide.md所描述的工作流正是从这类 docstring 模板产出docs/python-api/language/generated/下的 Markdown 文件。

与异步取数配套的接口

围绕异步取数,Matmul还提供了配套方法(同一源码文件内定义):

  • Matmul.wait_get_tensor_c:等待上一次异步取数完成,是异步路径的同步点;
  • Matmul.get_tensor_c:支持sync: bool = True参数,可同时设定sync=False走异步模式,即官方文档所说的"GetTensorC 异步接口";
  • Matmul.set_workspace:异步场景下需要一块临时空间缓存 iterate 计算结果,须在iterate之前调用。

官方建议的迁移方向:使用 get_tensor_c 异步模式

async_get_tensor_c的全部能力(把异步计算的 C 矩阵取到 LocalTensor)已被get_tensor_c覆盖。后者提供了更丰富的取数形态:

Matmul.get_tensor_c(tensor: BaseTensor, en_atomic: int = 0, en_sequential_write: bool = False, sync: bool = True, optional_tensor: BaseTensor | None = None) → None Matmul.get_tensor_c(en_atomic: int = 0, en_sequential_write: bool = False, sync: bool = True) → GlobalTensor

其取值目标既可以是 LocalTensor(VECIN),也可以是 GlobalTensor,还可通过optional_tensor同时输出到 GM 与 VECIN。异步模式下的标准范式(见 get_tensor_c 文档调用示例):

# 异步模式:iterate 不等待,循环内逐个取分片 mm.iterate(sync=False) # 其他操作 for i in range(single_m // base_m * single_n // base_n): mm.get_tensor_c(tensor=ub_cmatrix, sync=False)

以及"API 返回 GM 上的 C 矩阵、手动拷贝至 UB"的异步写法:

# base_m * base_n = 128 * 256 mm.set_tensor_a(gm_a) mm.set_tensor_b(gm_b) mm.set_tail(single_m, single_n, single_k) mm.iterate(sync=False) for i in range(single_m // base_m * single_n // base_n): global = mm.get_tensor_c(sync=False) for j in range(4): local = que.alloc_tensor(dtype=asc.half) asc.data_copy(local, global[64 * 128 * i:], count=64 * 128)

其中sync=Falseget_tensor_c即文档所指的"GetTensorC 异步接口",配合wait_get_tensor_c即可完成与旧接口等价的异步取数,同时获得输出到 GM、en_atomicen_sequential_write等扩展能力。因此新代码应优先采用get_tensor_c(sync=False)而非async_get_tensor_c

实践验证:单元测试中的完整异步链路

仓库单元测试 python/test/unit/language/adv/test_matmul.py#L300-L349(test_iterate_n_batch)给出了async_get_tensor_c的真实使用上下文,可用作自测与学习样例:

@asc.jit def kernel_iterate_n_batch(a, b, c, workspace) -> None: pipe = asc.TPipe() a_type = asc.adv.MatmulType(position=asc.TPosition.GM, format=asc.CubeFormat.ND, dtype=asc.float16, is_trans=False, layout=asc.LayoutMode.BSNGD) b_type = asc.adv.MatmulType(position=asc.TPosition.GM, format=asc.CubeFormat.ND, dtype=asc.float16, is_trans=True, layout=asc.LayoutMode.BSNGD) c_type = asc.adv.MatmulType(position=asc.TPosition.GM, format=asc.CubeFormat.ND, dtype=asc.float16, layout=asc.LayoutMode.BSNGD) matmul = asc.adv.Matmul(a_type, b_type, c_type) asc.adv.register_matmul(pipe, workspace, matmul) tiling = asc.adv.TCubeTiling(used_core_num=24, m=512, k_a=512, k_b=512, n=512, base_m=64, base_k=64, base_n=64, single_core_m=256, single_core_k=256, single_core_n=256, depth_a1=1, depth_b1=1, step_m=1, step_n=1, share_mode=0, share_ub_size=0, share_l1_size=asc.property(asc.TOTAL_L1_SIZE), share_l0c_size=asc.property(asc.TOTAL_L0C_SIZE)) matmul.init(tiling) # ... set_tensor_a / set_tensor_b / set_hf32 / set_tail / iterate_n_batch ... matmul.set_workspace(workspace, 1024) matmul.wait_get_tensor_c() x_local = asc.LocalTensor(dtype=asc.float16, pos=asc.TPosition.VECIN, addr=0, tile_size=512) matmul.async_get_tensor_c(c=x_local) matmul.end()

从该测试可以提取出使用async_get_tensor_c的关键事实:

  • 目标缓冲区c为 VECIN 位置(asc.TPosition.VECIN)的LocalTensor,即结果矩阵落在统一缓冲区(UB)的 VECIN 侧;
  • 调用时机:在wait_get_tensor_c()之后调用,二者构成"等待计算结果就绪 → 异步搬运结果"的配对;
  • 生命周期:与iterate_*系列(如iterate_n_batch)、set_workspaceend同处一个 JIT kernel 中,说明它属于 Matmul 迭代计算流水线的一部分;
  • tiling 前提base_m/base_n决定了单次取出的矩阵分片尺寸,接口本身不感知全局形状,分片逻辑由外层循环负责。

使用约束与注意事项

  1. MixDualMaster 双主模式不适用:当模板参数enableMixDualMaster设置为true时,不支持使用async_get_tensor_c(同样也不支持get_tensor_citerate的某些形态,详见各接口文档的约束说明)。涉及双主模式的场景需改用其他取数路径。
  2. 仅限 JIT kernel 内调用@require_jit约束意味着不能在普通 Python 脚本中直接调用,必须位于@asc.jit装饰的算子函数内。
  3. 已被功能替代:接口文档明确标注其功能已被get_tensor_c覆盖。除非维护历史代码,否则新实现应迁移至get_tensor_c(sync=False)异步模式,以获得 GM 输出、en_atomicen_sequential_write等扩展能力。
  4. set_workspace的配合:异步场景需要临时空间缓存 iterate 计算结果,须在iterate之前通过set_workspace预置(该约束同样适用于get_tensor_c的异步用法)。

小结

async_get_tensor_c是 pyasc Matmul 高阶 API 异步取数的早期形态,其职责单一——把 Iterate 异步计算的结果矩阵搬运到 VECIN 上的 LocalTensor,底层对应 Ascend C 的AsyncGetTensorC。虽然该接口功能已被get_tensor_c异步模式覆盖并建议弃用,但理解它有助于把握 Matmul 异步流水线"iterate(sync=False) → wait_get_tensor_c → 异步取数"的核心脉络。在实际开发中,请优先选择 get_tensor_c 的sync=False形态,并结合 iterate、wait_get_tensor_c、set_workspace 构建完整、可上板的异步 Matmul 算子。

【免费下载链接】pyasc本项目为Python用户提供算子编程接口,支持在昇腾AI处理器上加速计算,接口与Ascend C一一对应并遵守Python原生语法。项目地址: https://gitcode.com/cann/pyasc

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询