> The biggest speedup you’ll ever get with a program will be when you first get it working.
>你能获得的对程序最大的加速比就是当你第一次让它工作起来的时候。
—John K. Ousterhout
> ![存储器山](https://upload.wikimedia.org/wikipedia/commons/thumb/b/b4/MemoryMountain17.png/300px-MemoryMountain17.png)
* 当然, 一个**程序首先要能运行起来**。 即使是姿势再丑, 再笨拙,再怎么屌丝, 先让程序无bug的跑起来再说。
* 选择**一组合适的算法和数据结构。**算法和数据结构是程序的**灵魂**。
* **编写出编译器能够有效优化以转换成高效可执行代码的源代码。** 对于这一点, 理解编译器的一些基本能力, 特性以及局限性真的很总要。 编写程序方式中看上去只是一点小小的变动, 都会引起编译器优化方式很大的变化。 由于编译器原理很复杂, 各个编译器, 以及优化层次选择的不同, 优化方式可能有很大的变化。 所以,想要编写出精致高效的代码, 良好的风格以及不断的经验积累才是王道。
* 针对处理运算量特别大的计算, 将一个任务分成多个部分, 这些部分可以在多核和多处理器的某种组合上并行的计算---- **多线程并行算法** 。
程序员必须在实现和维护程序的简单性与它的运行速度之间做出权衡。
具体方法
-
掌握常用的高效的数据结构和算法。 至少要熟悉模板的使用。
-
消除循环的低效率, 尽量减少循环次数。 尽量不要在循环里 循环计算一些不会改变的值。
-
消除不必要的存储器引用。 尽量使用临时变量来暂存要多次使用的引用值,避免寻址开销。
-
防止寄存器溢出。 临时变量也并不是越多越好, 因为寄存器总是有限的,如果需要同时使用的临时变量数超过了可用的寄存器数量,编译器会把临时值存放到栈中。 一旦出现这种情况, 性能会急剧下降。(x86-64代码能够同时累积最多 12 个值, 而不会溢出任何寄存器。)
-
循环展开。 通俗的说就是利用分治的策略来减小循环的迭代次数。
-
提高并行性。 大多数情况下,程序的代码都不是按部就班的一步一步从上往下执行的, 它会适当的并行一些不相依赖的代码行。 所以尽量编写不相依赖的代码, 能够提高运行效率。
-
编写利于分支预测的代码。 在 CPU 执行分支时, 会预测程序朝哪一个分支方向执行。 如果预测错误会被罚时。
处理方法一般是
(1): 编写能被预测的分支。
(2):书写条件传送实现的代码, 不依赖分支预测。
-
利用存储器结构体系 :由于存储器山的存储器结构,利用了 时间局部性 和 空间局部性 的代码, 能极大的提高缓存命中, 从而使程序执行的更快。
-
多线程编程: 适当的应用多线程, 特别是多CPU的情况下, 程序的性能666的飞起。
-
多线程 + 线程池: 多线程的进阶版本。
-
参考资料:
*《深入理解计算机系统》
*《Java Web Programming》