在本文中,我将介绍一些的最常见的拖垮性能的一些编程代码,并推荐相应的解决方法,为你的 Python 涡轮增压!当然,如果你不限于此,推荐你看下前面推荐 mojo 语言 比 Python 快几万倍:比Python快9万倍!AI编程语言Mojo正式开源。
01 循环
我们通常对for
循环情有独钟,在需要进行大量作业时,首先想到的就是使用 for 循环。而在优化速度时,尤其是在讨论大型数据集时,这些循环简直就是噩梦般存在。
数字加法:将一大串数字的平方相加,首先使用一个循环方法:
numbers = [1, 2, 3, 4, 5, ... , 10000] # A big list
total = 0
for number in numbers:
squared = number * number
total += squared
在引擎下,Python 会对每个元素进行大量的单独计算。
解决方法:NumPy
这时,NumPy 就像超级英雄一样,它的矢量化简直无敌!一次性对整个数组执行操作。
import numpy as np
numbers = np.array([1, 2, 3, 4, 5, ... , 10000])
squared = numbers * numbers # Vectorized squaring!
total = squared.sum()
NumPy 不需要逐个元素计算,而是一气呵成地处理整个计算过程。
折中方案
列表推导式:
total = sum(number * number for number in numbers)
它们通常比传统循环更快,但在进行高强度数值计算时,可能无法与 NumPy 匹敌。
02 错用工具
对于 Python 来说,仅仅依靠列表来完成所有任务无异于只用一只手编程。
查询电话号码:假设有一个这样的联系人列表:
contacts = [
{"name": "Alice", "phone": "123-4567"},
{"name": "云朵君", "phone": "789-0123"},
# ... more contacts
]
查找云朵君的号码意味着要扫描列表,可能要检查每一个联系人。
解决方法:具有超能力的数据结构
如果要通过关键字(如 "姓名")进行搜索,字典就是你的救星。
contacts_dict = {
"Alice": "123-4567",
"云朵君"
: "789-0123",
# ... more contacts
}
bobs_number = contacts_dict["云朵君"] # Instant access!
需要跟踪唯一的网站访问者吗?集合会自动删除重复项。
unique_visitors = set()
unique_visitors.add("192.168.1.100")
unique_visitors.add("124.58.23.5")
unique_visitors.add("192.168.1.100") # No duplicate added
Python 还提供了更多超级有用的工具:有序字典、特殊队列 deques 等。了解何时使用这些工具标志着优秀与卓越脚本之间的区别。
03 在黑盒中优化
你一定对这种感觉很熟悉,虽然发现了代码运行缓慢,但却对原因一无所知时。这就好比在没有灯光的情况下修灯泡。
假设你有一个计算斐波那契数字的函数。你费尽心力来完善数学推理,但速度仍然很慢。结果发现,瓶颈可能是某些看不见的东西,比如在边运行代码边将结果记录到磁盘文件中。
解决方法:cProfile 来救场!
Python 内置的cProfile
模块就是你的性能侦探。下面介绍如何使用它:
import cProfile
def my_function():
# Your code to be profiled
cProfile.run('my_function()')
这将生成大量统计数据。主要内容如下
- cumtime: 与 tottime 类似,但包括调用其中所有函数所花费的时间。
筛选线索这些数字将指出真正的瓶颈,帮助你将优化工作集中在影响最大的地方。
04:重复造轮子
重新造轮子就像决定徒步穿越整个国家,而不是乘坐飞机前往目的地。就像上一步介绍的python工具一样,其实Python 真的有很多神奇的内置函数来帮助你完成你的工作。要不然python怎么会被戏称胶水语言呢。
排序:可以编写自己的冒泡排序实现......或者使用 Python 的sorted()
:
my_list = [5, 3, 1, 4, 2]
# The long way (probably pretty slow)
def my_bubble_sort(list):
# ... your sorting code here
# The Pythonic way
sorted_list = sorted(my_list)
很有可能,你的自定义排序算法甚至无法达到内置算法的效率。当然,如果你是编程超级高手,不用在意这些🤓
解决方法:借助标准库
Python 标准库简直就你最好最强大的朋友。比如用来解决本次问题的强大的工具有:
- itertools: 使用迭代器为你的工作增效(想想高级循环的效率)
- bisect:以迅雷不及掩耳之势让排序列表保持有序。
学习内置标准库的时间就是节省下来的优化时间。
05:与硬盘交互太多
将电脑内存(RAM)视为超快速工作区,将硬盘视为另一端的存储仓库。每次访问或修改文件,就相当于派遣一名信使来回奔波。往返次数过多,你的代码就会开始感觉到等待时长。就像第三节提到的,边运行代码,边存储文件到磁盘,还有往复读取、写入的更糟糕的过程。
逐行缓慢:假设正在处理一个庞大的日志文件:
with open("huge_log.txt", "r") as file:
for line in file:
# Process each line slowly
- 每读取
line
,就意味着要从硬盘上单独取一次数据。
解决方法:更聪明地工作,而不是更努力地工作
- 一次读完(如果合适): 对于较小的文件,有时最快的方法是将其全部读入内存:
with open("huge_log.txt", "r") as file:
contents = file.read()
# Process contents in memory
- 缓冲拯救: 当你需要细粒度的控制时,缓冲功能就能拯救你:
with open("huge_log.txt", "r") as file:
while True:
chunk = file.read(4096) # Read in chunks
if not chunk:
break
# Process the chunk
以块为单位,而不是以字节为单位思考尽量减少前往 "仓库" 的次数,这将带来巨大的不同。