工作后的读书笔记
最后更新于:2022年6月25日 下午
书依然在看,笔记不是很想写了
optim_cpp
为何软件经常很慢
- 硬件过去几十年飞速发展,但是现在到达了物理上的瓶颈
- 软件速度的递减速度快于硬件的增长
解决办法
- 设计多进程多线程
- 提高代码效率
优化的代价
以前,硬件性能还不行的时候,推荐不要把单次执行的代码当作子模块来使用,但是现在工程越来越大,这种做法会带来很多的问题,如何均衡性能和可读性可维护性呢?
- 隔离核心代码
- 对具体代码的某些部分进行优化
- 如何在不明显降低性能的情况下处理异常:边界检验,野指针等
- 要了解哪些构造函数是开销
库的选择
相对耗时的组件
- 文件 IO
- 音频图像处理
- 内存和字符串处理
- 数学函数
- 加密解密,数据处理
然而标准库并非对所有这些耗时的模块都很好的优化了,因此可以根据需求调用不同的库。
C++ 的缺点
- 跨平台是基于语言标准以及主流平台的支持。C++ 可以直接操作硬件(当然此时就做不到跨平台了)所以基本上此时我们就需要模块分开
- 开发时间:可用模块化和可复用的类显著降低
- 安全:边界检测和野指针等通常是黑客攻击的地方。有必要给出一个准则来处理安全问题,但这也可能先来效率的下降。
安全详解
比如有一个数组 \(a[3]\) 和数字 \(b\),那是否我访问 \(a[3] = x\) 就能改变 b 的值呢?
- 边界检测:用 vector(但是这会影响效率)
- 字符串:String 也是低效的(更有效的做法是用内存池,不懂不懂不懂)
- (整数)溢出:C 标准未定义有符号的溢出,因此各个编译器实现不同,当然可以加参数(
-ftrapv, -Wstrict-overflow=2, -fwrapv, -fno-strict-overflow
)来处理这些溢出(或者提前 check)
内存访问
- L1 缓存: 8 - 64 k
- L2 缓存:256k - 2 M
- L3 缓存:1G 左右
以上数值范围随着时间增加,但是不会很离谱的增加,mac 可通过
sysctl -a | grep "size"
查看
网络和硬件问题
这些都是无法保证的,因此需要考虑失效后怎么处理,网络有指数规避策略,硬件可以申请重试。
流水线
现代计算机都是流水线设计,即使是单核的 CPU,只要执行的指令无依赖,都可以流水线完成
我以前以为
a = ++b
比a = b++
快,因为前者不需要再生成一个变量,但是其实后者快,因为后者可被流水线优化(实测发现速度没差别)
选择优的算法
反对过度优化:如果一个普通的算法就能快速解决问题,就不要用高级和复杂的算法
Pragmatic Programmer
发现问题,不急不忙的分析的品质,不会?没关系,学,问别人,是成为一个程序员的自我修养
实事求是的哲学
在所有的弱点中,最大的弱点就是害怕暴露弱点。 J.B.Bossuet 1709
- 备份你的代码
- 遇到问题:提供各种选择,而非找蹩脚的理由(想想别人听你的理由会怎么想)
- 保持代码,文档的优雅
- 让你的用户参与权衡,知道你自己想说 什么
实事求是的途径
不要重复
DRY(Don't Repeat Yourself):不要重复自己
原则:系统中的每一项只是都必须具有单一,无歧义,权威的表示
代码中的文档:糟糕的代码才需要注释,注释会不可避免地变得过时
减少重复,但是不影响使用缓存
1 |
|
这上面就重复了,但是有时候 length 数据很难得到,这个时候为了效率我们就可能会需要缓存,即
1 |
|
但是上述做法只适用于单线程
写复用性更好的代码
正交性
- 各个模块相互不影响,解耦
- 提高生产力
- 降低风险
- 更利于拓展
- 文档也可以做成满足正交性
实事求是的偏执
- 你不可能写出完美的软件
- 需求之坑
- 文明通过增加文明不假思索就能完成的重要操作的数量而取得进步
文档
内部版和外部版
为自己的作品署名
不要重复,因此自解释的代码不需要注释
性能之巅
技术工程师如何发展
- 确定自己喜欢软件技术,愿意在技术上持久发展
- 日日新,又日新
- 逐级攀登软件技术的三级阶梯:编码,调试,调优(张银奎)
- 相信量变引起质变
未知的未知:我不知道我不知道
设计
- 如果一款小工具需要费力的说明,那很可能这是一个失败的设计
- 性能这块领域是,“你知道的越多,你不知道的也就越多”。这和学习系统是一样的原理:你了解的越多,你就能意识到未知的未知就越多,然后这些未知的未知会变成你可以去查看的已知的未知
- 性能指标不是免费的,在某些时候,会消耗一些 CPU 周期来手机和保存指标信息。对目标的性能会有负面影响,这种影响被称为观察者效应
ProGit
- stream of snapshots 不太现实吧!(要相信压缩的技术)
- git checkout