Stream管理
本节介绍单Stream、多Stream的创建、销毁流程,以及多Stream同步等待的流程。
在AscendCL中,Stream是一个任务队列,应用程序通过Stream来管理任务的并行,一个Stream内部的任务保序执行,即Stream根据发送过来的任务依次执行;不同Stream中的任务并行执行。一个默认Context下会挂一个默认Stream,如果不显式创建Stream,可使用默认Stream。默认Stream作为接口入参时,直接传NULL。
AscendCL提供以下几种Stream管理机制,其中,多Stream场景下的同步等待流程请参见多Stream时的同步等待流程:
单线程单Stream
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "acl/acl.h" // ...... // 显式创建一个Stream aclrtStream stream; aclrtCreateStream(&stream); // 调用触发任务的接口,传入stream参数 aclrtMemcpyAsync(dstPtr, dstSize, srcPtr, srcSize, ACL_MEMCPY_HOST_TO_DEVICE, stream); // 调用aclrtSynchronizeStream接口,阻塞应用程序运行,直到指定Stream中的所有任务都完成。 aclrtSynchronizeStream(stream); // Stream使用结束后,显式销毁Stream aclrtDestroyStream(stream); // ...... |
单线程多Stream
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include "acl/acl.h" // ...... int32_t deviceId = 0; uint32_t modelId1 = 0; uint32_t modelId2 = 1; aclrtContext context; aclrtStream stream1; aclrtStream stream2; // 如果只创建了一个Context,线程默认将这个Context作为线程当前的Context; // 如果是多个Context,则需要调用aclrtSetCurrentContext接口设置当前线程的Context aclrtCreateContext(&context, deviceId); aclrtCreateStream(&stream1); // 调用触发任务的接口,例如异步模型推理,任务下发在stream1 aclmdlDataset *input1; aclmdlDataset *output1; aclmdlExecuteAsync(modelId1, input1, output1, stream1); aclrtCreateStream(&stream2); // 调用触发任务的接口,例如异步模型推理, 任务下发在stream2 aclmdlDataset *input2; aclmdlDataset *output2; aclmdlExecuteAsync(modelId2, input1, output2, stream2); // 流同步 aclrtSynchronizeStream(stream1); aclrtSynchronizeStream(stream2); // 释放资源 aclrtDestroyStream(stream1); aclrtDestroyStream(stream2); aclrtDestroyContext(context); // .... |
多线程多Stream
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include "acl/acl.h" // ...... void runThread(aclrtStream stream) { int32_t deviceId =0; aclrtContext context; // 如果只创建了一个Context,线程默认将这个Context作为线程当前的Context; // 如果是多个Context,则需要调用aclrtSetCurrentContext接口设置当前线程的Context aclrtCreateContext(&context, deviceId); aclrtCreateStream(&stream); // 调用触发任务的接口 // .... // 释放资源 aclrtDestroyStream(stream); aclrtDestroyContext(context); } aclrtStream stream1; aclrtStream stream2; // 创建2个线程,每个线程对应一个Stream std::thread t1(runThread, stream1); std::thread t2(runThread, stream2); // 显式调用join函数确保结束线程 t1.join(); t2.join(); |
多Stream时的同步等待流程
开发应用时,如果涉及多Stream之间的任务等待,则应用程序中必须包含相关的代码逻辑,关于该场景的接口调用流程,请依次参见AscendCL接口调用流程以及本节中的说明。
多Stream之间任务的同步等待可以利用Event实现,调用aclrtStreamWaitEvent接口阻塞指定Stream的运行,直到指定的Event完成。需在调用aclrtStreamWaitEvent接口前,先调用aclrtRecordEvent接口。调用示例请参见Stream间任务的同步等待示例代码。
模型加载与执行的流程请参见基础推理应用。
算子加载与执行的流程请参见单算子调用。