电子产业一站式赋能平台

PCB联盟网

搜索
查看: 639|回复: 0
收起左侧

深入分析 C++ 错误处理:哪种策略的性能最强?

[复制链接]

475

主题

475

帖子

4237

积分

四级会员

Rank: 4

积分
4237
发表于 2024-9-23 09:00:00 | 显示全部楼层 |阅读模式
点击上方“C语言与CPP编程”,选择“关注/置顶/星标公众号
干货福利,第一时间送达!
最近有小伙伴说没有收到当天的文章推送,这是因为微信改了推送机制,确实会一部分有小伙伴刷不到当天的文章,一些比较实用的知识和信息,错过了就是错过了。所以建议大家加个星标??,就能第一时间收到推送了。

e5kxozwhbba6402304057.png

e5kxozwhbba6402304057.png

在 C++ 开发中,错误处理是一个至关重要的组成部分。不同的错误处理策略不仅会影响代码的可读性和可维护性,还会对应用程序的性能产生重大影响。为了深入了解各种错误处理技术在性能上的差异,本文作者进行了基准测试。本次测试旨在提供清晰的性能洞察,帮助开发者在实际应用中选择最合适的错误处理方法。
原文链接:https://johnfarrier.com/c-error-handling-strategies-benchmarks-and-performance/
错误处理是许多 C++ 应用程序中的关键部分,我们也有许多策略可以用来处理错误。最近,我想更好地了解 C++ 中各种错误处理技术对性能的影响。
1、C++ 错误处理实验设置我决定对不同的技术进行基准测试,看看它们的性能如何。为此,我使用了 Celero C++ 微基准测试库,以此清楚地了解每种方法的性能。
例如,std::expected 在可读性和可维护性方面有很多优点,同时考虑它的性能特征也很重要。通常,std::expected 比 exception(异常)更有效,因为它避免了堆栈展开的开销,而这在性能关键型应用程序中可能非常重要。
我构建了一个基准测试来比较以下 C++ 错误处理策略:
● 使用返回 true/false 表示成功/失败(Baseline)
● 使用错误代码(Error Code)返回值
● 使用 std::expected
● 使用 std::optional
● 使用 std::variant
● 使用 Callback
● 使用 std::exception
该 C++ 错误处理基准测试是用 Celero C++ 微基准测试库构建的。关于 C++ 错误处理基准测试的具体代码可查看:https://github.com/DigitalInBlue/celeroErrorHandlingBenchmark。
2、错误处理实验结果以下是原始输出结果:

4pywtxhjo3s6402304157.png

4pywtxhjo3s6402304157.png

为简化起见,以下是这些技术相对性能的精简版本:

ynuv0j3kle26402304257.png

ynuv0j3kle26402304257.png

在基线(Baseline) 归一化性能的情况下,使用 std::expected 慢约 2.1 倍。
3、性能比较排除 std::exception 后,C++ 错误处理基准测试结果表明,各种错误处理技术在性能上存在显著差异:

gaohjtzv2tk6402304357.png

gaohjtzv2tk6402304357.png

● Baseline(基线) :基线方法是返回 true 或 false,是最快的技术,平均每次迭代耗时 0.00324 微秒。
● std::expected:使用 std::expected 比基线慢约 2.18 倍,平均每次迭代耗时 0.00707 微秒。
● Error Code(错误代码):使用 Error Code 几乎与基线一样快,平均每次迭代耗时 0.00329 微秒。
● Optional:使用 std::optional 较慢,平均每次迭代耗时 0.00578 微秒,比基线慢约 1.78 倍。
● Variant:使用 std::variant 是非异常技术中最慢的,平均每次迭代耗时 0.00919 微秒,比基线慢约 2.83 倍。
● Error Callback(错误回调):使用 Error Callback 对性能影响的中等,平均每次迭代耗时 0.00429 微秒,比基线慢约 1.32 倍。
● Exception(异常):使用 std::exception 明显比所有其他技术都慢,平均每次迭代耗时 160.59420 微秒,比基线慢约 49,540 倍。
4、详细分析和意见(1)可读性与性能之间的权衡:
虽然 std::expected 和类似结构(如 std::optional,std::variant)提供了更具可读性和可维护性的代码,但同时也带来了相应的性能成本。在可读性和可维护性至关重要、而对性能要求不高的应用程序中,这些结构具有优势;然而,在对性能要求较高的应用程序中,可能更偏向于使用简单的错误处理方法。
通常情况下,我们建议在整个应用程序中选择一种错误处理方法,但有时可能也需要一种“默认”的错误处理方式(如使用 std::expected)和一种在特定情况下使用的“高性能”替代方案。
(2)不同情况下的错误处理策略:
高性能系统:对于需要高性能的系统,如实时系统或高频交易平台,应首选开销最小的错误处理技术,如返回代码或错误回调。
现代 C++ 应用程序:受益于现代 C++ 范式且对性能要求不太高的应用程序,可以用 std::expected 和 std::optional 获得更好的代码表达能力。
(3)Exception(异常)的影响:
异常带来的巨大开销(比基线慢 49,540 倍)凸显了为何在性能关键的代码中避免使用异常的原因。异常处理期间的堆栈展开过程会导致相当大的延迟。不过,异常对于处理应用程序中对性能要求较低部分的意外或罕见错误情况非常有用。
(4)基准环境和条件:
需要注意的是,基准测试可能会受到运行环境的影响(例如,CPU,编译器优化等)。本文提供的结果是针对特定基准条件下的结果,应根据你的具体应用进行验证。
(5)内存使用注意事项:
虽然运行时性能至关重要,但内存使用也是一个重要因素。基准测试结果表明,大多数技术(不包括例外情况)的内存使用情况相似,这说明错误处理方法的选择对内存占用的影响可能微乎其微。
(6)可组合性和集成性:
std::expected 和 std::optional 与其他现代 C++ 特性集成得很好,可能会简化复杂的错误传播场景。
5、关于 C++ 错误处理的建议根据基准测试结果,C++ 错误处理技术的选择应由应用程序的具体需求决定。以下是一些建议:
● 性能关键型应用:使用简单的错误处理方法,如返回代码或错误回调,尽量减少开销。
● 现代、可维护的代码:使用 std::expected 或 std::optional 以提高代码的清晰度和可维护性,尤其是在可以接受轻度性能开销的情况下。
● 异常处理:将异常保留给意外或不常发生的错误,因需要全面的错误信息,所以巨大的开销也算合理。
这些 C++ 错误处理基准测试强调了根据应用程序的性能需求选择正确错误处理技术的重要性。尽管 std::expected 和其他现代 C++ 特性提供了更好的可读性和可维护性,但它们对性能的影响也不容忽视,尤其是在对性能要求极高的应用程序中。
本文转自公众号“CSDN”,ID:CSDNnews——EOF——你好,我是飞宇。日常分享C/C++、计算机学习经验、工作体会,欢迎点击此处查看我以前的学习笔记&经验&分享的资源。
我组建了一些社群一起交流,群里有大牛也有小白,如果你有意可以一起进群交流。

angzzhn4re36402304457.png

angzzhn4re36402304457.png

欢迎你添加我的微信,我拉你进技术交流群。此外,我也会经常在微信上分享一些计算机学习经验以及工作体验,还有一些内推机会。

oaqbdw2okmg6402304557.png

oaqbdw2okmg6402304557.png

加个微信,打开另一扇窗
经常遇到有读者后台私信想要一些编程学习资源,这里分享 1T 的编程电子书、C/C++开发手册、Github上182K+的架构路线图、LeetCode算法刷题笔记等精品学习资料,点击下方公众号会回复"编程"即可免费领取~

感谢你的分享,点赞,在看三  

mtdstxhrfhh6402304657.gif

mtdstxhrfhh6402304657.gif

回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表