问题源自于工作中碰到的一次线上性能问题。线上日志显示了频繁的异常捕获,然后线上服务质量开始下滑。原因是C++ try..catch异常生产导致了服务不稳定。
某次,做了一次日常算法配置变更,对重排rerank的abtest控制参数下发到服务器。做了一次版本号的重命名。rerank_4_251变更到list_rerank_251,这里的下划线隔开的第二个字母,以前是4,现在是rerank。没想到代码里面有个专门解析这个编码的发生异常了。
这段代码如下所示,其中抛异常的是这个boost:lexical_cast。
来追踪一下boost::lexical_cast的源码就会发现。与 atof() 等函数在看到无效字符时立即停止解析不同,lexical_cast 要求输入字符串中的每个字符都有效。即任何前导或尾随空格将导致它抛出异常。
说到这里倒也正常,上线之前做次完整的测试环境测试和灰度环境测试,不就完了吗。但是重点在于,上线之前,这个代码压根没有抛出异常。(待补充)
这里有好处也有坏处,好处是代码变得严谨了,程序运行时会按照预设的逻辑允许,如果出现了错误(异常也是一种C++错误处理),可以及时通过日志告知,而且服务不至于奔溃,但是同样的,异常生成和处理(主要是try...cache(exception e) 在异常抛出时,生成exception的工作会让效率大打折扣,因为这个exceptionm可能含有大量的错误信息),会使得服务质量变得不稳定。
C++ 异常仍然不受每个实时环境的支持,使它们在任何地方都可以接受。
在视频游戏场景下,程序中异常处理就会显着减慢它的速度并增加代码大小,无论如何你是否真的抛出异常。最重要的是,抛出异常很慢并且可能导致堆释放。
来看看谷歌的C++风格指南怎么说,以下是谷歌c++指南的机器翻译版本。
从表面上看,使用异常的好处大于成本,尤其是在新项目中。但是,对于现有代码,异常的引入对所有依赖代码都有影响。如果异常可以传播到新项目之外,那么将新项目集成到现有的无异常代码中也会出现问题。而且异常替代方法(例如错误代码和断言)也不会会带来重大负担。
从语言机制来看,不像java,C++不会对异常进行编译期检查。从C++17开始,不能再从函数写可能抛出某种异常。只能声明不能抛出某种异常noexcept,如果一个函数声明不会抛异常,结果抛出异常,C++运行时会调用std::terminate来终止应用程序。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。