代码的精简与性能谁更重要

21CTO社区导读:本文最初发布在Arne Mertz个人博客“Simplily C++”上。在近3年和140个帖子里,本文是他写过的文章(http://arne-mertz.de/2015/03/simple-and-clean-code-vs-performance/)里访问量和讨论最多的帖子。“Simplilly C++”(简化C++)是关于讨论现代C++与代码简洁方面的博客。

代码的精简与性能谁更重要

C++的优点之一,可以编写出非常优秀的代码。但是这是否意味我们不用去考虑性能,将我们的日常代码写成尽可能好的性能。我们应该放弃简单性能吗?我们需要吗?

我不这么认为

有许多原因,让我不认为我们应该牺牲简单又干净的代码去追求性能方面的代码,相反地,我更倾向提倡为简单可能做出性能牺牲。

我宁愿请大家默认写简单干净的代码。好的,这很明显,因为我的博客就命名为“简化C++”。为什么这么认为呢?下面是我的观点。

性能并非效率

首先要明确的一点是,我们必须把性能和效率区分清楚。这两者分别代表什么,有什么不同?

简单来说,我们做的事情执行时有多快的速度(性能)以及它需要我们花费多长时间去完成(效率)。

刚一看好像差不多少,但其实不然。举个例子,假设你需要从A点到B点,效率意味着“最短路径”,性能意味着“以跑代走”。因此,即使以博尔特的速度到达终点,虽然高性能,但并不高效—“没有选择最短路径”。

对于编程来说,循环通常会耗费不少时间。此种情况下,性能意味着“单个循环用时越短越好”,效率意味着“尽量降低循环层数”,这里需要我们有一个更智能的算法。

有时候我们在这个世界上鱼与熊掌不能兼得。有效的算法可能让性能变得更不好。在尝试在代码中挤压性能之前,请确保高效率。只有测试了效率方面所有的可能性,再去考虑性能。

性能并非程序的全部

这是很浅显的道理,但往往容易被忽视,特别是程序员新手。在不少编程论坛和StackOverflow上,询问某段代码性能优化的提问比比皆是。

有个说法是80% 的程序运行时间是由约 20% 代码决定的,还有的人说是 90%/10%。确切的数字并不重要,关键是对程序来说,关键运算代码可能仅存在于某小部分代码中。因此,如果把精力放在所有代码的优化上,而不重点主攻关键代码,就成了事倍功半。

我们不需要写高性能的代码?

我心里知道,我也不敢说这样的话。

事实上,决定程序运行时长主要的因素是处理器处理指令数的多少,那些不是我们写的而是由编译器及其优化器写的。

优化器种类各种各样,除非您也是该领域的专家,否则也很难明白它对代码做了哪些优化工作。优化器可以销毁临时对象,可以内联函数,可以清除更多其它冗余的指令。

所以当这些不确定因素存在时,我们还能写出绝对高性能代码吗?如果真的很在意性能,我建议使用工具来辅助完成。

但也不必太悲观。如果有两种或更多的方法来写出同样可读的代码,那么不妨选择最高性能的写法。例如,在不存储结果的情况下,可以使用++iter 来代替 iter++。

性能和简洁并不总是相互矛盾

影响程序运行时间的另一个重要因素,甚至超过指令数量,它是内存中数据的布局和结构。有关内容可以详细参考 Chandler Carruth 的文章 Efficiency with Algorithms, Performance with Data Structures,用正确的数据结构来获得更佳的性能一文,这里不做赘述。

我要补充的是,假如你的数据的内存布局不好,那么会造成要花费很多时间来从获取数据,同时会造成指令冗余。

在开始调整代码来提高性能之前,请你确保使用性能最好的数据结构。另外还有一点,在使用系统或第三方库也需要选择性能好、简单的库。那些库的作者通常是最聪明的程序员,他们知道如何编写优质代码,而且也非常了解如何利用编译器来优化性能。所以,如果使用库而不自己再造轮子,代码可以更强大,且维护简单,也更高效。

当然,你要充分了解要使用的库,通过分析来看它的性能是否还不错。

对于代码简洁和性能的关系,你还可以参考文章“Using the libraries you have, and using them right”。

小结

建议默认编写出可读和简单的代码。如果你真的发现存在性能问题并已经找出它的位置,那么仍然有很多选择来对此进行处理而不必为了追求快速而写出复杂的代码。不到万不得已不要为了性能而牺牲简洁性,同时要学会始终用分析工具来处理性能问题。

译者:洛逸

代码的精简与性能谁更重要