昇腾 编程范式 - 矢量编程流水任务设计
flyfish
编程范式简单来说就是不同编程风格或方式的“套路”。按着套路走就可以。
矢量算子编程范式把算子的实现流程分为3个基本任务:CopyOut,Compute,copyout
CopyIn负责数据搬入操作,
Compute负责矢量计算操作,
CopyOut负责数据搬出操作
代码解释使用C++标准库实现,容易编译
TQue<QuePosition::VECOUT, 10> outQueueZ
形式的解释
QuePosition 枚举:
定义了 VECIN 和 VECOUT,用来区分输入队列和输出队列。
TQue 模板类:
TQue 类模板接收两个模板参数:一个是 QuePosition 枚举值,用来表示队列的位置;另一个是 BufferSize,表示队列的缓冲区大小。
TQue 类内部定义了一个 std::vector 作为缓冲区,enqueue 方法用于添加数据,dequeue 方法用于取出数据
仅用于语法解释,非线程安全
#include <iostream>
#include <vector>
// 定义枚举类型,表示队列位置或类型
enum class QuePosition {
VECIN, // 输入队列
VECOUT // 输出队列
};
// 定义模板类 TQue,模板参数为队列位置和缓冲区大小
template <QuePosition Position, size_t BufferSize>
class TQue {
public:
TQue() {
buffer.resize(BufferSize);
}
// 模拟添加数据到队列中
void enqueue(const int& data) {
if (size < BufferSize) {
buffer[size++] = data;
} else {
std::cerr << "Queue is full!" << std::endl;
}
}
// 模拟从队列中取出数据
int dequeue() {
if (size > 0) {
return buffer[--size];
} else {
std::cerr << "Queue is empty!" << std::endl;
return -1; // 返回-1表示队列为空
}
}
private:
std::vector<int> buffer; // 队列缓冲区
size_t size = 0; // 当前队列中的元素数量
};
int main() {
// 实例化输入和输出队列对象
TQue<QuePosition::VECIN, 10> inQueueX, inQueueY; // 输入队列
TQue<QuePosition::VECOUT, 10> outQueueZ; // 输出队列
// 向输入队列添加数据
inQueueX.enqueue(1);
inQueueY.enqueue(2);
// 从输出队列取出数据
int dataX = inQueueX.dequeue();
int dataY = inQueueY.dequeue();
// 输出结果
std::cout << "Dequeued from inQueueX: " << dataX << std::endl;
std::cout << "Dequeued from inQueueY: " << dataY << std::endl;
return 0;
}
使用 Double Buffer 技术优化计算
代码仅用于解释,使用两个缓冲区来实现这一技术,使得在一个缓冲区进行计算的同时,另一个缓冲区可以进行数据搬运操作。
#include <iostream>
#include <thread>
#include <vector>
// 模拟数据搬运(从内存拷贝数据到缓冲区)
void copyIn(int* buffer, int size) {
for (int i = 0; i < size; ++i) {
buffer[i] = i;
}
std::cout << "Copy In Complete" << std::endl;
}
// 模拟数据搬运(从缓冲区拷贝数据到内存)
void copyOut(int* buffer, int size) {
// 模拟将数据输出到某个位置
for (int i = 0; i < size; ++i) {
// 这里仅作示范,不实际搬运数据
}
std::cout << "Copy Out Complete" << std::endl;
}
// 模拟矢量计算
void compute(int* buffer, int size) {
for (int i = 0; i < size; ++i) {
buffer[i] *= 2; // 简单的计算,将每个元素乘以2
}
std::cout << "Compute Complete" << std::endl;
}
int main() {
const int bufferSize = 100;
int tensor1[bufferSize];
int tensor2[bufferSize];
// 启动双缓冲优化
std::thread copyInThread(copyIn, tensor1, bufferSize); // 对 tensor1 进行数据搬运
copyInThread.join();
std::thread computeThread1(compute, tensor1, bufferSize); // 对 tensor1 进行计算
std::thread copyInThread2(copyIn, tensor2, bufferSize); // 同时对 tensor2 进行数据搬运
computeThread1.join();
copyInThread2.join();
std::thread computeThread2(compute, tensor2, bufferSize); // 对 tensor2 进行计算
std::thread copyOutThread(copyOut, tensor1, bufferSize); // 同时对 tensor1 进行数据搬出
computeThread2.join();
copyOutThread.join();
std::thread copyOutThread2(copyOut, tensor2, bufferSize); // 最后对 tensor2 进行数据搬出
copyOutThread2.join();
std::cout << "Double Buffering Complete" << std::endl;
return 0;
}
输出
Copy In Complete
Copy In Complete
Compute Complete
Compute Complete
Copy Out Complete
Copy Out Complete
Double Buffering Complete
上面写的代码模拟copyIn、copyOut、compute 函数:
copyIn 函数模拟从内存将数据搬运到缓冲区中。
copyOut 函数模拟从缓冲区将数据搬运到内存中。
compute 函数对缓冲区中的数据进行计算。在这个例子中,计算内容很简单:将每个元素乘以2。