- Go语言高效编程:原理、可观测性与优化
- (波兰)巴特洛米·普洛特卡
- 2518字
- 2025-05-07 12:18:23
1.4 本章小结
笔者认为,软件研发人员在开发过程中为了完成目标而做出妥协是很常见的,比如通过牺牲一些效率、可读性、可测试性来保证按期交付。但在本章中,笔者建议开发人员对软件质量要有苛刻的自我要求,坚持不要去牺牲任何关于质量的特性,除非万不得已。对于有些绕不开的问题,只要稍加努力并借助适当的工具,也能妥善将其解决。
本章介绍了性能是由准确率、速度、效率构成的,以及业界对于性能问题的常见误解。我们认识到了过早悲观、过早优化、过早扩展带来的结果。最后,在性能的优化过程中,我们了解到优先优化效率才是正确的方向。
在下一章中,笔者会介绍Go语言。在优化Go程序性能之前,必须对它有足够的认知,不然一切都是纸上谈兵。
[1]为了证明这一点,笔者甚至在Twitter上做了一个小实验(https://oreil.ly/997J5)。
[2]剑桥词典中对性能一词的定义(https://oreil.ly/AXq4Q):一个人、机器等完成工作或活动的表现如何。
[3]笔者建议变更日志使用标准格式,可以参考https://oreil.ly/rADTI,该材料还包含如何清理release notes的宝贵建议。
[4]这里能使用“less performant”(低性能)吗?不能,因为英语词汇中不存在performant这个词。这里也不能使用高低性能来形容软件——因为软件的性能总有提升的空间。从实际意义上讲,软件的速度总是有限的。H.J.Bremermann在1962年提出了一个概念:存在一个依赖于系统质量的计算次数物理极限(https://oreil.ly/1sl3f)。根据这个概念就可以进行估算,1kg重的高配笔记本计算机每秒大约可以处理1050bit,而地球质量大小的计算机每秒最多也就可以处理1075bit。虽然这些数字看起来异常大,但即使用如此大的计算机处理复杂性为10120的国际象棋也需要花费很长时间(https://oreil.ly/6qS1T)。这些数字在密码学中有实际用途,可以用于评估破解某些加密算法的难度。
[5]值得一提的是,隐藏功能实现或优化细节可能会导致代码可读性降低。有时将它们呈现出来可以避免出现意外。
[6]最好在实现中注释说明可能出现的问题,以确保代码的稳定性和可靠性。
[7]Get方法的这三种实现方式的调用成本都很高。文件系统的I/O操作比从内存读取或写入内容要慢得多;涉及互斥锁意味着需要等待调度;访问数据库两者兼有,还涉及网络通信。
[8]这句名言经常被用来劝退那些尝试做优化工作的人,且经常被过度使用,它出自Donald Knuth的“Structured Programming with goto statements”(https://oreil.ly/m3P50)(1974)。
[9]这种变量风格通常被称为匈牙利表示法,它在微软公司中被广泛使用。匈牙利表示法有两种类型:匈牙利应用命名法(Apps Hungarian)和匈牙利系统命名法(Systems Hungarian)。有文献表明,匈牙利应用命名法在软件研发过程中可以带来很多益处(https://oreil.ly/rYLX4)。
[10]在开发时建议妥善使用IDE的某些功能来编写代码,例如,使用某些IDE编写出的代码可以构成“连通图”(connected graph)(https://oreil.ly/mFzH9)。这意味着借助IDE的功能可以方便地管理依赖关系。任何动态分派、代码注入和延迟加载都会导致这些功能被禁用,除非有特殊需求,否则应该避免影响这些功能的正常使用。
[11]认知负荷是指人在学习或完成任务过程中进行信息加工所耗费的认知资源的总量(https://oreil.ly/5CJ9X)。
[12]可缓存性(Cachability)被定义(https://oreil.ly/WNaRz)为数据被缓存的能力。任何信息都可以被缓存(保存),以便后续更快地检索。然而,缓存的数据可能只在短时间内有用,或者只对少量请求有用。那些依赖于外部因素(例如,用户或者输入)并且频繁更改的数据,就不适合被加入缓存。
[13]实际上,Thanos可能占用了更多内存,因为内存剖析结果不会显示内存映射、堆栈和操作系统缓存,第4章将介绍更多相关信息。
[14]西里尔·诺斯古德·帕金森(Cyril Northcote Parkinson)是一位英国历史学家,他提出了“帕金森定律”,该定律指出:“工作增多只是为了填满完成这项工作的时间”,作者试图传达的主要观点是:随着组织的发展,官僚主义也会扩大。
[15]其实笔者在学习时也是这样,这种现象也被称为“学生症候群”(Student Syndrome)(https://oreil.ly/4Vpqb),又称为“拖延症”。
[16]PB指petabyte,1PB=1024TB。如果一部时长两小时的4K电影占用100GB的磁盘空间,那么1PB的磁盘空间可以存储1万多部这样的电影,要连续观看两年多才能看完。
[17]1ZB=1024×1024PB=1024×1024×1024TB。
[18]Robert H.Dennard et al.,“Design of Ion-Implanted MOSFET's with Very Small Physical Dimension”(https://oreil.ly/OAGPC),IEEE Journal of Solid-State Circuits 9,no.5(October 1974):256-268.
[19]MOSFET(https://oreil.ly/mhc5k)即“金属-氧化物半导体场效应管”,被广泛用于电流开关控制与信号放大。它被证明具有高度的可扩展性和微型化能力,是历史上制造频率最高的电子设备,其数量是个天文数字。
[20]有趣的是,考虑到市场营销,芯片公司将CPU的命名规则从晶体管的栅极长度改为制程大小,以此来掩盖不能有效地通过制程来减小晶体管尺寸的这一事实。例如,14nm工艺的CPU仍然使用70nm的晶体管,那些10nm、7nm和5nm工艺的CPU也都是这样。
[21]笔者没有开玩笑,微软已经证实(https://oreil.ly/nJzkN),在水下40m处运行服务器是一个提高能源效率的绝佳方案。
[22]苹果公司的M系列芯片(https://oreil.ly/emBke)不走寻常路,在速度、能效与硬件扩展灵活性之间选择了速度与能效。
[23]RISC-V是开源指令集架构标准,RISC-V指令集可以自由地用于任何目的,允许任何人设计、制造和销售RISC-V芯片和软件。这种指令集非常简单,能够做出比通用CPU更专精的硬件。
[24]为了确保开发人员能够理解那些网速较慢的用户,Facebook推出了“2G Tuesdays”(https://oreil.ly/fZSoQ)活动,该活动会在Facebook应用程序上模拟2G网络模式。
[25]在AWS上购买这样的云实例其实并不贵,比如,实例类型x1e.32xlarge每小时收费26.6美元(https://oreil.ly/9fw5G),每月仅需支付19418美元。
[26]即使是硬件配置极高的机器,其管理方式也有所不同。这就是为什么Linux会有hugemem类型的内核,它可以更稳定地管理x86架构下的超大内存。
[27]CAP定理(https://oreil.ly/EYqPI)是一个分布式系统设计原则。其名称由一致性(Consistency)、可用性(Availability)和分区容忍度(Partition tolerance)的首字母拼接而成,指的是在一个分布式系统中,这三个要素最多只能同时实现两个,不可能三者兼顾。
[28]拒绝服务攻击(Denial of Service,DoS)是一种使目标系统停止响应的攻击手段,一般是因系统过载而被触发。
[29]大约在2015年,它成为波兰速度最快的超级计算机,运算速度能达到1.41PFlop/s,提供超过1600个节点,其中大部分节点配备了专用的GPU。
[30]无限带宽(InfiniBand)是一种高性能的网络通信标准,它在光纤通信发明之前非常流行。
[31]有趣的是,马克·扎克伯格却在2014年的F8大会上宣布将Facebook的口号改为“Move Fast with Stable infra”(快速行动,稳定基建)(https://oreil.ly/Yt2VI)。
[32]在云原生领域,有一个常见的案例是将日志从Elasticsearch迁移到更轻量级的组件,如Loki。尽管Loki缺乏可配置的索引,但它占用更少的资源,并提供更好的日志读取性能。
[33]当然还有其他原因,“Efficient Go”这个名字非常接近于Go语言领域的最佳文档“Effective Go”(https://oreil.ly/OHbMt)。该文档也对笔者有启蒙作用,权威且可操作性强,强烈推荐Go开发者阅读。