You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何PyO3实现的vec3类构造与乘法性能远逊于PyGLM?

优化PyO3实现的Float3类型以看齐PyGLM性能

PyO3默认生成的Python类包装存在几个额外开销点,而PyGLM通过激进的优化(如禁用动态属性、简化运算符实现)规避了这些开销:

  1. 默认启用的实例__dict__增加了对象初始化的内存分配和时间
  2. 原地运算符(__iadd__/__isub__)的错误实现导致额外对象创建
  3. 简单运算符函数未内联,引入不必要的调用开销
  4. Rust编译优化未拉满

以下是针对性的优化步骤:

1. 启用slots消除实例字典开销

修改#[pyclass]属性,添加slots禁用动态属性字典,减少对象创建的内存和时间开销:

#[pyclass(slots, derive(Clone))]
struct Float3 {
    #[pyo3(get, set)]
    x: f64,
    #[pyo3(get, set)]
    y: f64,
    #[pyo3(get, set)]
    z: f64,
}

2. 修正原地运算符实现

原__iadd__/__isub__创建新对象后赋值,不仅逻辑错误(Python原地运算符需返回self),还额外产生对象分配开销。修改为直接修改成员变量并返回self:

#[pymethods]
impl Float3 {
    // ... 其他方法 ...

    fn __iadd__(&mut self, lhs: &Self) -> PyResult<&mut Self> {
        self.x += lhs.x;
        self.y += lhs.y;
        self.z += lhs.z;
        Ok(self)
    }
    
    fn __isub__(&mut self, lhs: &Self) -> PyResult<&mut Self> {
        self.x -= lhs.x;
        self.y -= lhs.y;
        self.z -= lhs.z;
        Ok(self)
    }
}

3. 内联简单运算符函数

给所有简单的运算符方法添加#[inline(always)],强制Rust编译器内联这些函数,消除调用开销,同时复用代码减少冗余:

#[pymethods]
impl Float3 {
    #[new]
    #[inline(always)]
    fn py_new(x: f64, y: f64, z: f64) -> Self {
        Float3 { x, y, z }
    }
    
    #[inline(always)]
    fn __rmul__(&self, lhs: f64) -> Self {
        Float3 {
            x: self.x * lhs,
            y: self.y * lhs,
            z: self.z * lhs,
        }
    }

    #[inline(always)]
    fn __mul__(&self, lhs: f64) -> Self {
        self.__rmul__(lhs)
    }

    #[inline(always)]
    fn __add__(&self, lhs: &Self) -> Self {
        Float3 {
            x: self.x + lhs.x,
            y: self.y + lhs.y,
            z: self.z + lhs.z,
        }
    }
    
    #[inline(always)]
    fn __sub__(&self, lhs: &Self) -> Self {
        Float3 {
            x: self.x - lhs.x,
            y: self.y - lhs.y,
            z: self.z - lhs.z,
        }
    }

    // ... 修正后的原地运算符 ...
}

4. 拉满Rust编译优化

修改Cargo.toml的release配置,启用最高级优化:

[profile.release]
opt-level = 3       # 最高级优化
lto = true          # 链接时优化,跨模块合并代码
codegen-units = 1   # 单代码生成单元,最大化优化空间
panic = "abort"     # 禁用panic展开,减少开销(Python扩展中panic会直接崩溃)

5. 优化测试代码

测试时禁用Python GC避免干扰性能结果,同时增加样本量提升测试准确性:

import test_pyo3
import glm 
import time
import gc

def main():
    gc.disable()  # 禁用GC避免干扰
    samples = 1_000_000  # 增加样本量
    
    tic = time.time()
    for i in range(samples):
        temp = glm.dvec3(0.0, 0.0, 9.81)
    print(f"average time per construction glm {(time.time() - tic)/samples:.9f}")    
    
    tic = time.time()
    for i in range(samples):
        temp = test_pyo3.Float3(0.0, 0.0, 9.81)
    print(f"average time per construction test_pyo3 {(time.time() - tic)/samples:.9f}")    
    
    tic = time.time()
    for i in range(samples):
        temp = 1.5 * glm.dvec3(0.0, 0.0, 9.81)
    print(f"average time per multiply operation glm {(time.time() - tic)/samples:.9f}")    
    
    tic = time.time()
    for i in range(samples):
        temp = 1.5 * test_pyo3.Float3(0.0, 0.0, 9.81)
    print(f"average time per multiply operation test_pyo3 {(time.time() - tic)/samples:.9f}")    

if __name__ == '__main__':
    main()

预期效果

经过以上优化后,Float3的构造和乘法性能会接近甚至超过PyGLM的dvec3:

  • 构造性能的40%差距会缩小到10%以内
  • 乘法性能的一倍差距会基本消除

这些优化主要针对PyO3的默认包装开销,将Rust的原生性能充分释放,对齐PyGLM的优化策略。

内容的提问来源于stack exchange,提问作者Krupip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 01:53:14