第16章:性能优化、并发与最佳实践
OCCT 是一个庞大的算法库,既能处理数毫米的精密件,也要支撑数十万零件的装配。性能与稳定性是工程化部署的核心问题。本章总结性能调优思路、并发能力与开发最佳实践。
1. 测量先于优化
任何优化前先用 OSD_Timer 或 OSD_Chronometer 测量:
OSD_Timer t; t.Start();
// 算法
t.Stop();
std::cout << "elapsed=" << t.ElapsedTime() << "s\n";
OCCT 还有:
Message_Report自动收集步骤耗时;Standard_Tools::WhatThread()调试多线程;Graphic3d_FrameStats渲染帧率;- 外部工具 perf、vtune、Instruments。
2. 算法级优化
2.1 选择正确的数据结构
- 拓扑遍历用
TopTools_IndexedMapOfShape而非std::set<TopoDS_Shape>; - 频繁查找用
NCollection_DataMap+ 自定义 Hasher; - 大量小对象用
NCollection_BaseAllocator池分配器。
2.2 减少重复求交
- 布尔运算
SetGlue(BOPAlgo_GlueShift|GlueFull)跳过装配中“确知不相交”的零件; - 自定义
BRepBndLib包围盒预筛; - 把多次
Cut(a, b)、Cut(a, c)合并为BRepAlgoAPI_BuilderAlgo多操作数版本。
2.3 让几何变简单
- 解析几何替代 NURBS(
GeomConvert::CurveToBSplineCurve反操作BRepLib::ConvertToCanonical); ShapeUpgrade_UnifySameDomain合并相同曲面的相邻面,减少边/面数量;- 删除冗余
Compound。
2.4 控制容差
- 拒绝把全局容差当 fuzzy 用;
- 经过修复后再做布尔;
- 必要时
ShapeFix_ShapeTolerance限制最大值。
3. 并发能力
OCCT 多个核心算法支持并行(SetRunParallel(true)):
- BOP(
BRepAlgoAPI_*); - 网格化(
BRepMesh_IncrementalMesh、IMeshTools_Parameters::InParallel); - 圆角(部分算法);
- 数据交换(
STEPCAFControl_Reader::SetParallel、RWGltf_CafReader)。
后端:
- 内置
Standard_ThreadPool(OCCT 7.5+ 默认); - 可选 TBB(
USE_TBB=ON); - 用户也可使用
OSD_Parallel::ForEach并行循环:OSD_Parallel::ForEach(items.begin(), items.end(), [&](Item& it) { ... });
注意:
Handle(T)引用计数线程安全;- 同一
TopoDS_Shape的写操作不安全,需要拷贝; - AIS/V3d 必须在主线程使用;
- OCAF 文档应在持有事务的线程中写入。
4. 内存管理
- OCCT 大量使用引用计数 + 共享,多数情况下不需要手工释放;
- 对“一次性”大数据,使用作用域 +
Nullify()提前释放; NCollection_IncAllocator(增量分配器)适合算法局部数据;- 启用
MMGT_OPT=0/1/2环境变量切换 OCCT 内部分配器(默认系统 malloc)。
5. 避免常见陷阱
- 修改共享 TShape:先
BRepBuilderAPI_Copy; - 跨线程操作 AIS:在主线程;
- 频繁创建大
Compound:考虑层级聚合; - 重复网格化:调用
BRepTools::Clean清旧; - 未关闭的 fuzzy=0 BOP:会因数值误差失败,必要时设小 fuzzy;
- 未提供 PCurve:
BRepLib::BuildCurves3d修补; - 大装配
BRepBndLib::Add(shape, bb, true):精确包围盒慢,必要时退化到默认。
6. 编译期优化
- Release + LTO(GCC
-flto、MSVC/GL)显著加速; -O2通常优于-O3(OCCT 算法多分支不利于过度内联);- Windows 上勿混用 Debug runtime 与 Release lib,否则
Handle引用计数会异常; - 使用
Ninja+ ccache 加快迭代; - 大型应用按模块裁剪 OCCT,仅链接必要 toolkit。
7. 图形性能
BRepMesh偏差合理:linear 0.05–0.5 mm;- 关闭
FaceBoundaryDraw可大幅减线条; Graphic3d_RenderingParams::FrustumCullingState、OcclusionCullingState;- 使用
AIS_ConnectedInteractive实例化重复零件; - 批量更新时
view->SetImmediateUpdate(false); - 复杂场景启用
Graphic3d_RenderingParams::ToReduceAA简化反走样。
8. 异步与响应性
桌面应用中长时间算法应放后台线程,主线程负责进度显示与 UI 响应:
QtConcurrent::run([=]() {
Message_ProgressScope sc(progressRange, "BOP", 1);
BRepAlgoAPI_Cut cut(a, b);
cut.SetRunParallel(true);
cut.Build();
// 发信号回主线程
});
Message_ProgressIndicator 通过 ProgressRange 提供分级进度,可在 Qt 中绑定到 QProgressBar。
9. 发布与部署
- Linux:
patchelf/rpath让二进制找到 OCCT 库; - Windows:拷贝
*.dll与第三方依赖; - macOS:
install_name_tool修复 rpath; - 资源文件:
CSF_*环境变量保证 STEP/IGES/Plugin 配置可加载; - Web:Emscripten 编译,注意
Tcl不可用。
10. 编码规范建议
- 命名:类用
PascalCase,方法用PascalCase,宏用OCC_前缀; - 头文件:
Module_Class.hxx、源文件:Module_Class.cxx; - 句柄:始终
Handle(T) v = new T(...); - 异常:抛
Standard_Failure派生类,捕获时使用OCC_CATCH_SIGNALS; - 字符串:
TCollection_AsciiString与TCollection_ExtendedString边界要清晰; - 文档:Doxygen 注释,遵循
dox/dev_guides/coding_rules。
11. 测试与回归
- 把核心算法用 Draw 脚本覆盖,纳入
tests/; - C++ 集成测试用 GoogleTest,调用 OCCT API;
- 性能测试基线:
OSD_Timer+ 历史快照对比; - 几何回归:
BRepTools::Write黄金.brep文件; - 持续集成:GitHub Actions / GitLab CI 并行多平台构建 + 测试。
12. 故障定位
- 抛
Standard_Failure:GetMessageString含错误描述; - 内存崩溃:开 ASan/UBSan;
- 死循环:
OCC_CATCH_SIGNALS、Tcl 中Ctrl+C; - 几何异常:导出
.brep复现,分享给 OCCT 社区或自查; - BOP 内部错误:开启 Message_Report 看 warnings。
13. 监控与日志
Message_Messenger 默认输出到 stdout;可注册自定义 Message_Printer 写到文件、网络或 GUI 控件。建议在产品级软件中:
- 把 OCCT 警告/错误统一记录;
- 区分
Trace/Info/Warning/Alarm/Fail; - 开发态保留
Trace,生产态调高门槛。
14. 总结
性能与可靠性是 OCCT 应用的“两条腿”:
- 性能依赖正确的数据结构、算法选择、并行化与内存管理;
- 可靠性依赖容差控制、修复流程、异常处理与回归测试。
下一章我们看 OCCT 与外部生态的集成方式。