第八周读书笔记
2018-04-26 20:21 ccj1998 阅读(186) 评论(1) 编辑 收藏 举报本周继续阅读《计算机组成原理》
1、代码优化
基于前面的学习,我们得以获得一些提高代码性能的技术。首先我们知道了衡量程序性能往往用cpu时钟周期来参考。代码移动时最常见的优化手段,我们需要将一些循环低效率进行移动(例如移出循环)。其次我们应该减少过程调用,因为这会带来大量开销。我们还可以减少不必要的存储器调用,如引入临时变量。在每次迭代中执行更多的数据操作来减小循环开销。另外,使用指针而不是数组进行引用也能改进程序的性能。
必须要指出,优化的性能是有限的,并且我们需要在程序的简单性和运行速度之间进行权衡折中,因为优化往往伴随着抽象性的降低。
2、储存器结构
在以前的模型中,存储器系统是线性的,而cpu能够在一个时间常数内访问每个存储器的位置。实际上,存储器系统具有层次结构,有cpu寄存器、RAM、DISK等,他们的速度、容量、价格都依次降低。层次结构兼顾了价格与性能。硬盘访问有寻道、旋转、传送三部分时间,导致了读取第一位的代价最昂贵。每一储存层次中往往储存了最近用过的数据和其临近数据。此外,RAM、cpu磁盘间的速度差距正在进一步增大,以上种种事实要求我们的程序应该有良好的时间局部性和空间局部性。时间局部性指被引用过的存储器元素在不久的将来要再次用到,空间局部性指被引用过的存储器元素附近的元素可能在不久的将来要用到。良好的局部性意味着计算机可以减少对下一层存储系统的访问,从而大大减少时间开销。通过储存器山,我们看到,工作集越小,读吞吐率越高;步长越小,读吞吐率越高,山脊代表了使用到的储存层次发生变化。在矩阵乘法的6个版本中,我们发现程序性能与缺失率有着极大的关联,最快版本比最慢的运行得快了近3倍。更广泛的,我们可以通过分块运算的方法来提高局部性,但这同时也会使代码难以理解。
3、链接
链接就是将不同部分的代码和数据收集组合为一个单一文件的过程,这个文件可以被加载到储存器并执行。链接让我们能够模块化地编写大程序,并且改变一个源文件不需要重新编译其他源文件,具有高效性。创建可执行文件的过程中,连接器要完成符号解析和重定位两个主要任务。接下来我们了解了可重定位目标文件格式。在处理多处定义的符号时,连接器会根据强弱符号来解析,有三条处理规则,而这往往隐藏着危险。如,当重复定义多个弱符号时,编译器会从中任意选取一个而不会报错,这些都是我们以后编写程序要注意的。另外,为了解决打包程序员所用库函数的问题,提出了静态链接库的概念。相关的函数可以被编译为独立的目标模块,然后封装为一个单独的静态文件库。在链接时链接器将只拷贝被程序引用的目标模块,程序员需要输入的名字也更少。
4、异常控制流
异常就是控制流中的突变,用来响应处理器中的一些变化。异常可以分为四类:中断、陷阱、故障和终止。异常并不一定是“异常”的,如中断和陷阱,是有积极意义的,它们总是返回下一条指令。而故障由错误情况引起,根据故障能否被修复,故障处理程序要么重新执行故障指令,要么终止。终止则是不可恢复的致命错误导致的。
进程是正在运行的程序,它为每个程序提供了一个假象,好像程序在独立地占用处理器,实际上每个进程是轮流使用处理器的。进程被操作系统管理,控制流通过上下文切换从一个进程切换到另一个进程。值得一提的是,除了用户级程序,内核也可以在一台计算机上运行多个,比如虚拟机。
创建新进程需要调用fork函数,它返回0给子进程,返回子进程的pid给父进程,即调用一次,返回两次。有的进程在终止后仍在消耗系统资源,被称为僵尸进程。子进程一般由父进程回收,只有长期运行的进程需要显示回收,可用wait回收。
5、小结
阅读这本书让我看到了比c语言更底层的东西,让我从程序员的角度了解计算机系统的实现过程,理解程序的行为,以及效率低下的原因。为今后编写更高效可靠的代码打下了基础。