Mini-Infer (9): 打造高性能算子的基石 — RAII `Buffer` 与 `noexcept` 极致优化
Mini-Infer (9): 打造高性能算子的基石 — RAII Buffer 与 noexcept 极致优化
1. 技术深潜:noexcept 的奥义
在构建高性能 C++ 库时,我们经常看到 noexcept 这个关键字。它不仅仅是一个装饰,它是性能优化的关键开关。
noexcept 是 C++11 引入的一个关键字,它的作用非常明确:告诉编译器(和读代码的人),这个函数保证不会抛出任何异常。
1.1 核心作用:向编译器“承诺”不抛异常
当你把函数声明为 noexcept 时:
1 | void myFunc() noexcept { |
你是在立下一个“军令状”:“我保证这里面代码无论发生什么,都不会让异常飞出这个函数体。”
如果违背了誓言会怎样? 如果一个被标记为 noexcept 的函数真的抛出了异常,C++ 运行时不会尝试去捕获它,也不会进行“栈展开”(Stack Unwinding,即不会去析构局部对象)。程序会立即调用 std::terminate(),直接粗暴地崩溃(Crash)。
这意味着:noexcept 里的异常是无法被外部的 try-catch 捕获的。
1.2 为什么需要它?(为了性能!)
你可能会问:“如果它只会导致程序崩溃,我为什么要用它?” 答案是:性能优化,特别是对于标准库容器(如 std::vector)的优化。
场景:std::vector 扩容 当 std::vector 空间不足需要扩容时,它会申请一块更大的新内存,把旧数据迁移过去。
- 如果你的移动构造函数(Move Constructor)加了
noexcept: Vector 会放心地使用**移动(Move)**操作。把旧对象“搬”过去,成本极低(只是指针拷贝)。 - 如果你的移动构造函数没有加
noexcept: Vector 为了保证数据安全性(Strong Exception Guarantee),它不敢用移动。因为它怕移到一半抛异常了,旧数据已经被破坏(移走了),新数据也没建好,导致数据丢失。 所以,Vector 会退化成使用**拷贝(Copy)**操作。这对于大对象(如大的 Tensor)来说,性能是一个巨大的损失。
性能对比示例:
1 | class Tensor { |
1.3 什么时候应该用 noexcept?
通常建议在以下 4 种情况必须加:
- 移动构造函数 (Move Constructor):为了
std::vector优化。 - 移动赋值运算符 (Move Assignment Operator):同上。
- 析构函数 (Destructor):默认为
noexcept,除非你故意修改。 - 叶子函数 (Leaf Functions):明显不会抛异常的短小函数(如
get_size()),帮助编译器优化。
2. RAII 内存利器:Buffer<T>
在 Mini-Infer 中,Tensor 类用于在图的节点之间传递数据。它是基于 std::shared_ptr 的,带有引用计数,比较重。
而在算子内部(比如 Convolution 的 im2col 操作),我们需要一个临时的、轻量级的、独占的内存块。
为此,我们引入 Buffer<T>。
buffer.h 实现
1 |
|
3. 为什么 Buffer 比 std::vector 更好?
你可能会问:“为什么不直接用 std::vector<float>?”
- 统一的内存管理:
Buffer使用我们的Allocator接口。这意味着如果未来我们要统计整个模型的内存占用,或者切换到特定的内存池(Memory Pool),Buffer会自动遵循这些规则,而std::vector只会傻傻地调用系统new。 - 避免初始化开销(可选):
std::vector默认会构造所有元素。虽然我们在Buffer中也用了memset,但对于 POD 类型,这比vector的构造循环要快。在某些极致优化场景下,我们甚至可以去掉memset,只申请不初始化。 - 显式的 RAII:
Buffer明确表达了这是一个“临时工作区”的语义,且禁用了拷贝,防止了隐式的性能杀手。
4. 实战预览:Convolution 中的应用
在下一篇我们实现 Convolution 时,你将看到 Buffer 的威力。
没有 Buffer 的代码 (危险):
1 | // Bad Style |
使用 Buffer 的代码 (安全且优雅):
1 | // Good Style |
总结
通过引入 Buffer<T> 和正确使用 noexcept,我们不仅让代码变得更安全(RAII),还为未来的性能优化(移动语义)打下了基础。
现在,兵马未动,粮草先行。所有的工具都已齐备。





