CANN Runtime 内建任务实战指南:Reduce 归约与随机数生成的异步下发(aclrtReduceAsync / aclrtRandomNumAsync)
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
CANN Runtime 将归约(Reduce)、随机数生成等高频计算能力封装为内建任务(built-in task),应用可以直接通过aclrtReduceAsync、aclrtRandomNumAsync等 API 在 Stream 上异步下发,无需自行编写并编译算子内核,即可在 Device 侧完成数据归约与多分布随机数生成。本文基于本仓库example/2_advanced_features/built_in_task目录下的两个可运行样例,完整讲解这两类内建任务的使用流程、核心 API 结构体与参数语义、随机数算法与内存要求,并结合include/external/acl/acl_rt.h等源码级定义验证其底层接口契约。读完本文,你可以直接复现 Reduce 求和样例与五类随机数生成样例,并掌握在自有程序中正确组装aclrtRandomNumTaskInfo下发随机数任务的完整方法。
一、内建任务是什么
在 CANN 的编程模型中,绝大多数 Device 侧计算以**算子内核(Kernel)**形式下发:应用侧编译或加载内核二进制,再通过 Stream 提交执行。而内建任务是 Runtime 预先内置在 Device 侧的一类特殊任务,无需用户提供内核代码,只需通过几个专用 API 描述任务参数,即可完成一类标准化的数据操作。
example/2_advanced_features/built_in_task目录正是围绕这一能力组织样例的,包含两个子样例:
| 样例目录 | 演示能力 | 核心 API |
|---|---|---|
| 0_reduce_task | Reduce 任务的下发与结果读取(数组求和) | aclrtReduceAsync |
| 1_random_num_task | 随机数任务的下发与多分布生成 | aclrtRandomNumAsync |
两者共用同一套"初始化 → 设置 Device → 创建 Stream → 申请/拷贝内存 → 异步下发 → 同步 → 拷回结果 → 释放资源"的标准 Runtime 流程,差异只在于任务本身的参数组装方式。
二、产品支持情况
两个内建任务样例在产品上的支持情况略有差异,下表可直接作为选型参考:
| 产品 | Reduce 任务(0_reduce_task) | 随机数任务(1_random_num_task) |
|---|---|---|
| Ascend 950PR / Ascend 950DT | √ | × |
| Atlas A3 训练系列产品 / Atlas A3 推理系列产品 | √ | √ |
| Atlas A2 训练系列产品 / Atlas A2 推理系列产品 | √ | √ |
可以看到,随机数任务目前在 Ascend 950PR / Ascend 950DT 上暂不支持,在 Atlas A2 / A3 系列上两类任务均可运行。开发前请先核对目标硬件型号。
三、Reduce 归约任务
3.1 功能概述
归约(Reduce)是并行计算中的常见操作,对数组元素执行求和、求最大值、求最小值等聚合运算。在深度学习中,归约被广泛用于 loss 计算、梯度聚合、attention 内部的归一化统计等场景。通过aclrtReduceAsync,应用可以在不编写内核的情况下,把这段计算直接交给 Device 侧完成。
3.2 核心 API:aclrtReduceAsync
该 API 的原型在 include/external/acl/acl_rt.h 中声明:
ACL_FUNC_VISIBILITY aclError aclrtReduceAsync( void* dst, const void* src, uint64_t count, aclrtReduceKind kind, aclDataType type, aclrtStream stream, void* reserve);各参数说明:
| 参数 | 说明 |
|---|---|
dst | 输出地址,指向 Device 内存中存放归约结果的位置 |
src | 输入地址,指向 Device 内存中的源数据 |
count | 数据大小,单位为字节(注意不是元素个数,样例中传入count * sizeof(float)) |
kind | 归约类型,取值为aclrtReduceKind枚举 |
type | 输入/输出的数据类型,取值为aclDataType(如ACL_FLOAT) |
stream | 任务下发所在的 Stream |
reserve | 预留参数,当前传NULL |
返回ACL_SUCCESS表示调用成功,其他值表示失败;该调用本身是异步的,任务真正执行完成需要配合aclrtSynchronizeStream等待。
3.3 归约类型:aclrtReduceKind
aclrtReduceKind枚举定义在 include/external/acl/acl_rt.h:
typedef enum { ACL_RT_MEMCPY_SDMA_AUTOMATIC_SUM = 10, // 自动求和(前缀和) ACL_RT_MEMCPY_SDMA_AUTOMATIC_MAX = 11, // 求最大值 ACL_RT_MEMCPY_SDMA_AUTOMATIC_MIN = 12, // 求最小值 ACL_RT_MEMCPY_SDMA_AUTOMATIC_EQUAL = 13, // 相等比较 } aclrtReduceKind;从源码结构看,归约能力与 Runtime 的 SDMA(数据搬运引擎)自动模式绑定,因此这组枚举沿用了ACL_RT_MEMCPY_SDMA_AUTOMATIC_*的命名风格。Reduce 样例使用的ACL_RT_MEMCPY_SDMA_AUTOMATIC_SUM执行的是前缀和(扫描求和):输出数组的第 i 个元素等于输入数组前 i+1 个元素之和,而不是简单的单值归约——这正是样例输出中结果呈现递增累加的原因。
3.4 完整代码流程解析
样例主体见 0_reduce_task/main.cpp,完整流程如下:
#include <acl/acl.h> #include "utils.h" int main() { aclError ret; // 1. 初始化 ACL CHECK_ERROR(aclInit(NULL)); // 2. 指定用于运算的 Device CHECK_ERROR(aclrtSetDevice(0)); // 3. 创建 Stream aclrtStream stream; CHECK_ERROR(aclrtCreateStream(&stream)); // 4. 准备 Host 数据(4 个 float 元素) const int count = 4; float hostInput[4] = {1.0, 2.0, 3.0, 4.0}; float hostOutput[4] = {0, 0, 0, 0}; size_t size = count * sizeof(float); // 5. 申请 Device 内存 void* devInput = NULL; void* devOutput = NULL; CHECK_ERROR(aclrtMalloc(&devInput, size, ACL_MEM_MALLOC_HUGE_FIRST)); CHECK_ERROR(aclrtMalloc(&devOutput, size, ACL_MEM_MALLOC_HUGE_FIRST)); // 6. 拷贝数据到 Device CHECK_ERROR(aclrtMemcpy(devInput, size, hostInput, size, ACL_MEMCPY_HOST_TO_DEVICE)); CHECK_ERROR(aclrtMemcpy(devOutput, size, hostInput, size, ACL_MEMCPY_HOST_TO_DEVICE)); // 7. 异步下发 Reduce 任务(前缀和) ret = aclrtReduceAsync( devOutput, devInput, size, ACL_RT_MEMCPY_SDMA_AUTOMATIC_SUM, // 归约类型 ACL_FLOAT, // 数据类型 stream, NULL); CHECK_ERROR(ret); // 8. 同步等待 Stream 上的任务执行完成 CHECK_ERROR(aclrtSynchronizeStream(stream)); // 9. 将结果拷回 Host CHECK_ERROR(aclrtMemcpy(hostOutput, size, devOutput, size, ACL_MEMCPY_DEVICE_TO_HOST)); // 10. 打印结果 for (int i = 0; i < count; i++) { printf("Reduce SUM result[%d] = %f\n", i, hostOutput[i]); } // 11. 释放资源 aclrtFree(devInput); aclrtFree(devOutput); aclrtDestroyStream(stream); aclrtResetDeviceForce(0); aclFinalize(); return 0; }代码中的CHECK_ERROR宏来自 example/utils.h,它检查aclError返回值,非ACL_SUCCESS时打印错误信息并退出,是样例统一的错误处理方式。
几个值得注意的工程细节:
aclrtResetDeviceForce用于强制复位当前运算的 Device 并回收其上的资源,与普通释放相比更彻底,适合样例这种一次性运行的场景。dst与src指向同一块内存(或内容相同)是允许的:样例先把devOutput也填成输入值,再把归约结果写回devOutput,读者可以观察这种原地覆盖式用法。count的单位是字节,若元素是 float(4 字节),4 个元素即 16 字节。
3.5 示例输出
运行0_reduce_task后,预期输出如下(对应{1, 2, 3, 4}的前缀和序列):
Reduce SUM result[0] = 2.000000 Reduce SUM result[1] = 4.000000 Reduce SUM result[2] = 6.000000 Reduce SUM result[3] = 8.000000 [INFO] Sample run successfully.注意result[0]的值为 2.0 而不是 1.0,这是因为样例在dst中预先放置了与输入相同的内容,前缀和从输入首元素开始累加,因此result[0] = 1.0(原值) + 1.0(输入首元素)= 2.0,其余元素依此类推。若希望得到{1, 3, 6, 10}的纯前缀和结果,可将devOutput初始化为全 0(参考随机数样例中aclrtMemset清零的做法)。
四、随机数生成任务
4.1 功能概述
aclrtRandomNumAsync是 Runtime 提供的另一类内建任务:在 Device 侧直接生成指定分布、指定类型的随机数,并支持生成 Dropout 所需的 bitmask。它支持均匀分布、正态分布、截断正态分布与 Dropout bitmask 四种函数类型,且无需用户编写内核代码,非常适合初始化阶段的大规模随机数填充(如权重初始化、mask 生成)。
4.2 核心 API:aclrtRandomNumAsync
该 API 原型声明于 include/external/acl/acl_rt.h:
ACL_FUNC_VISIBILITY aclError aclrtRandomNumAsync( const aclrtRandomNumTaskInfo* taskInfo, const aclrtStream stream, void* reserve);| 参数 | 说明 |
|---|---|
taskInfo | 随机数任务信息,见下文aclrtRandomNumTaskInfo结构体 |
stream | 任务下发所在的 Stream |
reserve | 预留字段,当前传NULL |
与aclrtReduceAsync的"位置参数"风格不同,随机数任务的所有信息通过一个结构体聚合传递,因此参数组装是关键。
4.3 任务信息结构体:aclrtRandomNumTaskInfo
aclrtRandomNumTaskInfo定义在 include/external/acl/acl_rt.h:
typedef struct { aclDataType dataType; aclrtRandomNumFuncParaInfo randomNumFuncParaInfo; void *randomParaAddr; void *randomResultAddr; void *randomCounterAddr; aclrtRandomParaInfo randomSeed; aclrtRandomParaInfo randomNum; uint8_t rsv[10]; } aclrtRandomNumTaskInfo;字段语义如下:
| 字段 | 说明 |
|---|---|
dataType | 随机数的数据类型(ACL_FLOAT、ACL_FLOAT16、ACL_BF16及整数类型等) |
randomNumFuncParaInfo | 函数类型标识与分布参数(见 4.4) |
randomParaAddr | 分布参数所在设备地址;样例中参数直接内嵌在结构体中,此处传NULL |
randomResultAddr | 输出缓冲区(Device 地址),存放生成的随机数 |
randomCounterAddr | 随机数状态计数器(Counter)的 Device 地址,固定 16 字节 |
randomSeed | 随机种子,aclrtRandomParaInfo封装(见 4.5) |
randomNum | 生成的随机数个数,aclrtRandomParaInfo封装 |
rsv[10] | 预留字节,置 0 即可 |
4.4 函数类型与分布参数:aclrtRandomNumFuncParaInfo
函数类型枚举与参数联合体定义在 include/external/acl/acl_rt.h:
typedef enum { ACL_RT_RANDOM_NUM_FUNC_TYPE_DROPOUT_BITMASK = 0, // dropout bitmask ACL_RT_RANDOM_NUM_FUNC_TYPE_UNIFORM_DIS, // uniform distribution ACL_RT_RANDOM_NUM_FUNC_TYPE_NORMAL_DIS, // normal distribution ACL_RT_RANDOM_NUM_FUNC_TYPE_TRUNCATED_NORMAL_DIS, // truncated normal distribution } aclrtRandomNumFuncType; typedef struct { aclrtRandomNumFuncType funcType; union { aclrtDropoutBitmaskInfo dropoutBitmaskInfo; aclrtUniformDisInfo uniformDisInfo; aclrtNormalDisInfo normalDisInfo; } paramInfo; } aclrtRandomNumFuncParaInfo;其中分布参数结构体(acl_rt.h):
// dropout bitmask typedef struct { aclrtRandomParaInfo dropoutRation; } aclrtDropoutBitmaskInfo; // uniform distribution typedef struct { aclrtRandomParaInfo min; aclrtRandomParaInfo max; } aclrtUniformDisInfo; // normal distribution typedef struct { aclrtRandomParaInfo mean; aclrtRandomParaInfo stddev; } aclrtNormalDisInfo;4.5 参数封装:aclrtRandomParaInfo
分布参数、种子、数量统一用aclrtRandomParaInfo封装,定义在 include/external/acl/acl_rt.h:
typedef struct { uint8_t isAddr; uint8_t valueOrAddr[8]; uint8_t size; uint8_t rsv[6]; } aclrtRandomParaInfo;isAddr:0 表示valueOrAddr中直接存放立即值,非 0 表示valueOrAddr中存放设备内存地址(参数在 Device 内存中);valueOrAddr[8]:8 字节缓冲区,既可作为立即值的存储区,也可作为地址使用;size:参数字节数;rsv[6]:预留。
样例中所有参数均采用立即值方式(isAddr = 0),例如 1_random_num_task/main.cpp 中组装均匀分布参数:
*((float*)taskInfo.randomNumFuncParaInfo.paramInfo.uniformDisInfo.min.valueOrAddr) = min; taskInfo.randomNumFuncParaInfo.paramInfo.uniformDisInfo.min.size = sizeof(float); taskInfo.randomNumFuncParaInfo.paramInfo.uniformDisInfo.min.isAddr = 0;4.6 支持的分布类型与数据类型
(1)均匀分布(Uniform Distribution)
- 函数类型标识:
ACL_RT_RANDOM_NUM_FUNC_TYPE_UNIFORM_DIS - 支持数据类型:浮点
ACL_FLOAT、ACL_FLOAT16、ACL_BF16;整数ACL_INT32、ACL_INT64、ACL_UINT32、ACL_UINT64 - 参数:
min(最小值)、max(最大值)
(2)正态分布(Normal Distribution)
- 函数类型标识:
ACL_RT_RANDOM_NUM_FUNC_TYPE_NORMAL_DIS - 支持数据类型:
ACL_FLOAT、ACL_FLOAT16、ACL_BF16 - 参数:
mean(均值)、stddev(标准差)
(3)截断正态分布(Truncated Normal Distribution)
- 函数类型标识:
ACL_RT_RANDOM_NUM_FUNC_TYPE_TRUNCATED_NORMAL_DIS - 支持数据类型:
ACL_FLOAT、ACL_FLOAT16、ACL_BF16 - 参数:
mean(均值)、stddev(标准差)
(4)Dropout Bitmask 生成
- 用于生成随机失活(Dropout)的 bit mask,按比例生成
- 函数类型标识:
ACL_RT_RANDOM_NUM_FUNC_TYPE_DROPOUT_BITMASK - 参数:
ratio(dropout 比例,支持数据类型ACL_FLOAT、ACL_FLOAT16、ACL_BF16)
4.7 随机数算法
| 算法 | 特性 |
|---|---|
| Philox4_32_10 | 支持所有分布类型;Counter 为 128bit,需要 16Byte 存储 |
Philox4_32_10是一种基于计数器(counter-based)的伪随机数生成算法:给定 seed 与 counter 即可确定性地产出随机序列。由于是 counter-based 算法,同一个 seed 下改变 counter 可以并行生成互不重叠的随机序列,这对大规模并行初始化非常重要;同时它也要求用户为每个任务维护独立的 counter 状态(见 4.8)。
4.8 内存要求
根据文档与样例实现,随机数任务需要三类 Device 内存:
- Counter 内存:固定 16 字节,任意字节对齐地址即可。样例中先申请再清零:
constexpr size_t kCounterSize = 16U; void* counterAddr = nullptr; CHECK_ERROR(aclrtMalloc(&counterAddr, kCounterSize, ACL_MEM_MALLOC_HUGE_FIRST)); CHECK_ERROR(aclrtMemset(counterAddr, kCounterSize, 0, kCounterSize)); - 输出内存:根据数据类型和随机数数量动态分配。样例申请
num * sizeof(uint64_t)作为"足够大"的输出缓冲,以容纳不同位宽的结果:uint64_t num = 128; size_t size = num * sizeof(uint64_t); CHECK_ERROR(aclrtMalloc(&devOutput, size, ACL_MEM_MALLOC_HUGE_FIRST)); - 参数内存:均值、标准差、范围等参数既可使用立即值(内嵌在结构体的
valueOrAddr中),也可使用设备内存(isAddr = 1,valueOrAddr存地址)。样例统一使用立即值方式。
4.9 完整代码流程解析
随机数样例的完整骨架见 1_random_num_task/main.cpp,其任务下发模式如下(以正态分布 float 为例):
aclError NormalFloatAsync( float mean, float stddev, bool isTruncated, uint64_t seed, uint64_t num, void* counterDevAddr, void* devOutput, aclrtStream stream) { aclrtRandomNumTaskInfo taskInfo = {}; taskInfo.dataType = ACL_FLOAT; taskInfo.randomNumFuncParaInfo.funcType = isTruncated ? ACL_RT_RANDOM_NUM_FUNC_TYPE_TRUNCATED_NORMAL_DIS : ACL_RT_RANDOM_NUM_FUNC_TYPE_NORMAL_DIS; taskInfo.randomParaAddr = NULL; taskInfo.randomCounterAddr = counterDevAddr; taskInfo.randomResultAddr = devOutput; *((float*)taskInfo.randomNumFuncParaInfo.paramInfo.normalDisInfo.mean.valueOrAddr) = mean; taskInfo.randomNumFuncParaInfo.paramInfo.normalDisInfo.mean.size = sizeof(float); taskInfo.randomNumFuncParaInfo.paramInfo.normalDisInfo.mean.isAddr = 0; *((float*)taskInfo.randomNumFuncParaInfo.paramInfo.normalDisInfo.stddev.valueOrAddr) = stddev; taskInfo.randomNumFuncParaInfo.paramInfo.normalDisInfo.stddev.size = sizeof(float); taskInfo.randomNumFuncParaInfo.paramInfo.normalDisInfo.stddev.isAddr = 0; *((uint64_t*)taskInfo.randomSeed.valueOrAddr) = seed; taskInfo.randomSeed.size = sizeof(uint64_t); taskInfo.randomSeed.isAddr = 0; *((uint64_t*)taskInfo.randomNum.valueOrAddr) = num; taskInfo.randomNum.size = sizeof(uint64_t); taskInfo.randomNum.isAddr = 0; return aclrtRandomNumAsync(&taskInfo, stream, NULL); }主程序依次生成五组随机数并打印前 5 个结果,每组之间均执行"同步 Stream → 拷回 Host → 打印":
INFO_LOG("Generate normal distribution random numbers, data type: float"); float mean = 3.0; float stddev = 2.0; CHECK_ERROR(NormalFloatAsync(mean, stddev, false, seed, num, counterAddr, devOutput, stream)); CHECK_ERROR(aclrtSynchronizeStream(stream)); CHECK_ERROR(aclrtMemcpy(hostOutput.get(), size, devOutput, size, ACL_MEMCPY_DEVICE_TO_HOST));半精度类型(FP16 / BF16)在样例中直接以uint16_t表示并采用十六进制字面量构造数值,例如0x3F80即 BF16 的 1.0、0x4000即 2.0,打印时使用%#x:
BF16 meanBF16 = 0x3F80; // bf16(1.0) BF16 stddevBF16 = 0x4000; // bf16(2.0) CHECK_ERROR(NormalBF16Async(meanBF16, stddevBF16, true, seed, num, counterAddr, devOutput, stream));Dropout bitmask 生成与分布生成共用同一套接口,区别仅在于funcType改为ACL_RT_RANDOM_NUM_FUNC_TYPE_DROPOUT_BITMASK,并填充dropoutBitmaskInfo.dropoutRation:
float ration = 0.4; CHECK_ERROR(DropoutBitmask(ration, seed, num, counterAddr, devOutput, stream));4.10 示例输出
运行1_random_num_task后,预期输出结构如下(随机数值随种子不同而变化):
[INFO] Generate normal distribution random numbers, data type: float Random result[0] = ... ... [INFO] Generate truncated normal distribution random numbers, data type: BF16 Random result[0] = ... ... [INFO] Generate uniform distribution random numbers, data type: FP16 Random result[0] = ... ... [INFO] Generate uniform distribution random numbers, data type: INT32 Random result[0] = ... ... [INFO] Generate dropout bitmask, output data type: UINT8 Random result[0] = ... [INFO] Sample run successfully.五、编译与运行
5.1 前置环境
- 已安装 CANN 软件包(默认安装根目录为
/usr/local/Ascend); - 目标 Device 符合上文的"产品支持情况";
- 样例代码位于仓库 example/2_advanced_features/built_in_task 目录下,编译依赖头文件与
acl_rt库(CANN 安装包自带)。
5.2 编译运行步骤
在任意一个样例目录下执行:
# ${install_root} 替换为 CANN 安装根目录,默认安装在 /usr/local/Ascend source ${install_root}/cann/set_env.sh export ASCEND_INSTALL_PATH=${install_root}/cann # 编译并运行 bash run.sh环境安装详情与运行详情也可参见 example/README.md。
5.3 run.sh 脚本解析
两个样例的 run.sh 完全一致,核心流程为:
set -e # 获取 CANN 安装路径 _ASCEND_INSTALL_PATH=$ASCEND_INSTALL_PATH source $_ASCEND_INSTALL_PATH/bin/setenv.bash # 在脚本所在目录创建 build 目录并进入 BUILD_DIR="${SCRIPT_DIR}/build" mkdir -p "${BUILD_DIR}" cd "${BUILD_DIR}" # 执行 cmake 配置 cmake .. -DASCEND_CANN_PACKAGE_PATH=${_ASCEND_INSTALL_PATH} # 编译 make -j$(nproc) # 运行生成的可执行文件 ./build/main注意:脚本依赖ASCEND_INSTALL_PATH环境变量,这正是 5.2 中先export ASCEND_INSTALL_PATH=${install_root}/cann的原因。
5.4 CMake 配置要点
样例的 CMakeLists.txt 结构简洁,可供自有工程参考:
cmake_minimum_required(VERSION 3.16.0) project(Reduce_Sample) # 随机数样例为 Random_Num_Sample include_directories(${ASCEND_CANN_PACKAGE_PATH}/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../..) # 引入 example/utils.h link_directories(${ASCEND_CANN_PACKAGE_PATH}/lib64) add_executable(main main.cpp) target_compile_options(main PRIVATE -O2 -std=c++17 -D_GLIBCXX_USE_CXX11_ABI=0 -Wall -Werror ) target_link_libraries(main PRIVATE acl_rt )要点解读:
- 头文件搜索路径指向 CANN 安装包的
include目录,运行时库搜索路径指向lib64,链接库为acl_rt; -D_GLIBCXX_USE_CXX11_ABI=0与 CANN 发行库的 ABI 保持一致,避免链接期符号不匹配;-Wall -Werror将警告升级为错误,保证样例代码的严格性;- 额外 include 到
example顶层目录,是为了使用 example/utils.h 中定义的CHECK_ERROR与INFO_LOG宏。
六、接口契约的源码级印证
上文涉及的核心类型与函数均可在公开头文件中找到权威定义,可作为编写自有程序时的接口契约依据:
aclrtReduceAsync原型:include/external/acl/acl_rt.haclrtReduceKind枚举(SUM/MAX/MIN/EQUAL):include/external/acl/acl_rt.haclrtRandomNumAsync原型:include/external/acl/acl_rt.haclrtRandomNumTaskInfo结构体:include/external/acl/acl_rt.haclrtRandomNumFuncType枚举与分布参数联合体:include/external/acl/acl_rt.haclrtRandomParaInfo参数封装:include/external/acl/acl_rt.haclrtReduceAsync的 Host 侧实现位于 src/acl/aclrt_impl/memory.cpp,可据此进一步追踪其任务封装与下发的底层调用链。
七、注意事项与已知问题
- 字节单位:
aclrtReduceAsync的count参数是字节数而非元素个数,组装参数时务必乘以sizeof(type); - Counter 唯一性:随机数任务要求 Counter 为固定 16 字节、任意字节对齐的 Device 内存,多次下发需保证 Counter 状态连续正确(样例在首次使用前通过
aclrtMemset清零);从源码结构看,不同任务/不同线程若复用同一 Counter,需自行保证串行化或管理好状态; - 半精度字面量:FP16/BF16 参数需要以二进制位模式(十六进制)构造,切勿直接赋浮点常量;
- 产品差异:随机数任务在 Ascend 950PR/Ascend 950DT 上不支持,Reduce 任务在三个产品系列上均支持;
- 异步语义:两个 API 均为异步下发,读取结果前必须调用
aclrtSynchronizeStream等待任务完成,否则可能读到未就绪的数据; - 已知 issue:截至当前仓库版本,两个样例均标注"暂无"已知 issue。
总体而言,Reduce 与随机数生成是 Runtime 内建任务中最具代表性的两类能力:前者展示了"一个枚举+一次调用"即完成标准聚合计算,后者展示了"结构体聚合描述任务"的复杂参数传递模式。掌握这两类任务的组装方式后,迁移到其他内建任务时只需替换对应的 API 与参数结构,流程骨架完全一致。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考