本文目录导读:
- 算法与数据结构层面(收益最大)
- 代码实现与语言特性层面(针对具体编码)
- I/O 与外部资源访问(瓶颈常在此)
- 并发与异步(利用多核)
- 架构与设计层面(宏观优化)
- 微优化(要谨慎使用,优先保证可读性)
- 最重要的一点:避免过早优化
在保证正确性的前提下,提升运行速度、降低内存占用、提高可维护性,不同编程语言和场景的侧重点会有所不同,但以下是一些通用且常见的技巧,按类别整理供你参考:
算法与数据结构层面(收益最大)
这是最根本的优化,往往能带来数量级的提升。
-
选择更优的算法
- 降低复杂度:将冒泡排序(O(n²))替换为快速排序(O(n log n));将线性查找(O(n))替换为二分查找(O(log n)),前提是数据已排序或使用哈希表。
- 空间换时间:使用哈希表(字典/Map)将查找时间从 O(n) 降到 O(1);使用缓存(Memoization)避免重复计算。
-
选择合适的数据结构
- 查找多:用哈希表(HashMap)或二叉搜索树(TreeMap)。
- 顺序访问或频繁插入删除:链表(LinkedList)优于动态数组(如 ArrayList),因为数组的中间插入需要移动元素。
- 先进先出:使用队列。
- 优先级处理:使用堆(Heap)。
代码实现与语言特性层面(针对具体编码)
这部分熟练掌握常见语言的特性非常重要。
-
减少重复计算
- 循环外提:将循环内不变的表达式提到循环外面。
- 坏例子:
for i in range(len(arr)): do_something(arr[i], len(arr)) - 好例子:
n = len(arr); for i in range(n): do_something(arr[i], n)
- 坏例子:
- 缓存结果:对于昂贵的函数调用(如数据库查询、复杂计算),使用缓存(Memory Cache、
functools.lru_cache等)。
- 循环外提:将循环内不变的表达式提到循环外面。
-
减少内存分配与复制
- 预分配内存:如果能预知集合大小,提前分配好容量(如 Java 的
new ArrayList<>(10000),Python 的[None] * n)。 - 使用原地操作:在数组或列表上直接修改(
list.sort())而不是新建一个(sorted(list))。 - 避免隐式复制:在循环中拼接字符串时,用
StringBuilder(Java)/string.join()(Python)而非 或 。
- 预分配内存:如果能预知集合大小,提前分配好容量(如 Java 的
-
循环优化
- 减少函数调用:循环内的边界条件计算、对象属性访问等,尽量提取为局部变量。
- 循环展开:减少循环控制开销(现代编译器常自动做,手写需谨慎)。
- 更快的迭代方式:如 Java 中
for (int x : arr)比索引访问可能更优化;在 Python 中列表推导式通常比显式for循环快。
-
利用语言内置函数和库
- 语言内置函数(如 C 实现的
map()、filter()、sort())往往比手写的 Python 循环快得多。 - 使用成熟的数值计算库(如 NumPy)代替手写复杂的矩阵运算。
- 语言内置函数(如 C 实现的
I/O 与外部资源访问(瓶颈常在此)
-
批处理
- 减少 I/O 次数:不要逐行写入磁盘或发送网络请求,而是攒一批(如每 1000 条)再写。
- 使用缓冲:读写文件时使用缓冲流(Buffer),可以将多次小写入合并为一次大写入。
-
延迟加载 / 懒加载
只在真正需要时才创建对象、加载数据或建立连接,使用 Lazy Initialization 模式。
-
连接池
对于数据库、网络连接等昂贵资源,使用连接池复用,而不是每次请求都新建和销毁。
并发与异步(利用多核)
- 并行处理:将独立的任务分解,使用多线程或多进程运行(注意 GIL 的影响)。
- 异步 I/O:对于 I/O 密集型任务(如网络爬虫、Web 服务器),使用异步编程(
async/await)避免线程阻塞,提高吞吐量。 - 避免锁竞争:如果使用多线程,减少锁的粒度(如使用读写锁、无锁队列、CAS 操作),或采用无锁数据结构。
架构与设计层面(宏观优化)
- 懒加载 vs 预加载:根据数据访问模式决定,如果是必须的且耗时,可以启动时预加载;如果可能不需要,则懒加载。
- 缓存策略:使用多级缓存(CPU 缓存、进程内缓存、分布式缓存如 Redis、CDN 等)。
- 分治与分片:将大任务拆解为小任务并行处理(如 MapReduce 思想)。
微优化(要谨慎使用,优先保证可读性)
这些通常是最后才考虑的细节优化:
- 位运算代替数学运算:
x % 2 == 0可写成(x & 1) == 0;x * 2可写成x << 1。 - switch/case 代替 if/else if:当分支较多时,大部分语言中 switch 的跳转表效率更高。
- 字符串池化:在 Java 等语言中,使用
String.intern()减少重复字符串内存(需权衡性能)。
最重要的一点:避免过早优化
《代码整洁之道》与《重构》等经典书籍反复强调:
- 先写出正确、可读、可维护的代码。
- 用性能分析工具(Profiler)找到真正的瓶颈(往往与直觉不符)。
- 只优化瓶颈处的那 20% 的代码,它们通常决定了 80% 的性能。
示例流程:
写代码 -> 保持简洁 -> 运行发现卡顿 -> 使用 Profiler 定位到 Function A 消耗了 90% 的时间 -> 针对 Function A 的算法或数据结构进行优化 -> 重新测试验证。
希望这些分类能帮你在实际开发中更有针对性地优化代码,如果针对特定语言(如 Python、Java、C++)或场景(如 Web、游戏、数据处理),可以进一步深入讨论。
标签: 常见技巧