Context使用示例
单线程使用默认Context
对于简单应用,使用默认Context即可满足需求。调用aclrtSetDevice接口时,Runtime会自动创建默认Context,无需显式管理。
以下示例展示单线程使用默认Context的基础流程:
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 | // 1. 初始化Runtime aclInit(nullptr); // 2. 指定Device,自动创建默认Context和默认Stream int32_t deviceId = 0; aclrtSetDevice(deviceId); // 3. 创建显式Stream(可选,也可直接使用默认Stream传入nullptr) aclrtStream stream; aclrtCreateStream(&stream); // 4. 在Stream上下发任务 aclrtMemcpyAsync(devPtr, size, hostPtr, size, ACL_MEMCPY_HOST_TO_DEVICE, stream); myKernel<<<8, nullptr, stream>>>(devPtr, size); aclrtMemcpyAsync(hostPtr, size, devPtr, size, ACL_MEMCPY_DEVICE_TO_HOST, stream); // 5. 同步等待任务完成 aclrtSynchronizeStream(stream); // 6. 销毁显式Stream aclrtDestroyStream(stream); // 7. 复位Device,释放默认Context和默认Stream aclrtResetDeviceForce(deviceId); // 8. 去初始化 aclFinalize(); |
多线程并行计算
多个线程使用同一Device时,推荐为每个线程创建独立Context:
// 线程函数
void* threadFunc(void* arg) {
int32_t deviceId = *(int32_t*)arg;
// 每个线程创建自己的Context
aclrtContext ctx;
aclrtCreateContext(&ctx, deviceId);
// 创建Stream
aclrtStream stream;
aclrtCreateStream(&stream);
// 执行任务
// ... 业务逻辑 ...
// 同步等待任务完成
aclrtSynchronizeStream(stream);
// 销毁资源
aclrtDestroyStream(stream);
aclrtDestroyContext(ctx);
return nullptr;
}
// 主线程
int main() {
aclInit(nullptr);
int32_t deviceId = 0;
aclrtSetDevice(deviceId);
// 创建多个线程
pthread_t threads[4];
for (int i = 0; i < 4; i++) {
pthread_create(&threads[i], nullptr, threadFunc, &deviceId);
}
// 等待线程完成
for (int i = 0; i < 4; i++) {
pthread_join(threads[i], nullptr);
}
aclrtResetDeviceForce(deviceId);
aclFinalize();
return 0;
}
多线程Context共享
多个线程共享同一Context时,需自行保证Stream上任务的执行顺序:
aclrtContext g_ctx; // 全局Context
void* threadFunc(void* arg) {
int threadId = *(int*)arg;
// 切换到共享Context
aclrtSetCurrentContext(g_ctx);
// 创建线程专属Stream
aclrtStream stream;
aclrtCreateStream(&stream);
// 在自己的Stream上执行任务
// ... 业务逻辑 ...
aclrtSynchronizeStream(stream);
aclrtDestroyStream(stream);
return nullptr;
}
int main() {
aclInit(nullptr);
int32_t deviceId = 0;
aclrtSetDevice(deviceId);
// 创建一个Context供多线程共享
aclrtCreateContext(&g_ctx, deviceId);
pthread_t threads[4];
int threadIds[4];
for (int i = 0; i < 4; i++) {
threadIds[i] = i;
pthread_create(&threads[i], nullptr, threadFunc, &threadIds[i]);
}
for (int i = 0; i < 4; i++) {
pthread_join(threads[i], nullptr);
}
aclrtDestroyContext(g_ctx);
aclrtResetDeviceForce(deviceId);
aclFinalize();
return 0;
}
Context切换
使用aclrtSetCurrentContext切换当前线程的Context:
// 在Device 0上创建两个Context aclrtSetDevice(0); aclrtContext ctx1, ctx2; aclrtCreateContext(&ctx1, 0); aclrtCreateContext(&ctx2, 0); // 切换到ctx1 aclrtSetCurrentContext(ctx1); aclrtStream stream1; aclrtCreateStream(&stream1); // ... 在ctx1上执行任务 ... // 切换到ctx2 aclrtSetCurrentContext(ctx2); aclrtStream stream2; aclrtCreateStream(&stream2); // ... 在ctx2上执行任务 ... // 切换Context时,如果新Context属于不同Device,Device也会随之切换 aclrtSetDevice(1); aclrtContext ctx3; aclrtCreateContext(&ctx3, 1); aclrtSetCurrentContext(ctx3); // 当前Context切换为ctx3,Device也切换为1
Context参数配置
使用aclrtCtxSetSysParamOpt设置Context级别的参数:
aclrtContext ctx; aclrtCreateContext(&ctx, 0); // 设置Context参数(示例:设置内存配置) aclrtCtxSetSysParamOpt(ACL_SYS_PARAM_OPT_XXX, value); // 获取Context参数 int64_t paramValue; aclrtCtxGetSysParamOpt(ACL_SYS_PARAM_OPT_XXX, ¶mValue);
默认Stream获取
每个Context包含一个默认Stream,可通过接口获取:
aclrtContext ctx; aclrtCreateContext(&ctx, 0); // 获取当前Context的默认Stream aclrtStream defaultStream; aclrtCtxGetCurrentDefaultStream(&defaultStream); // 使用默认Stream(也可直接传nullptr) aclrtMemcpyAsync(dst, size, src, size, ACL_MEMCPY_DEVICE_TO_DEVICE, nullptr);
父主题: Context管理