Python性能优化技巧
一、性能分析工具
在优化之前,首先要找出性能瓶颈。
1.1 使用timeit测量执行时间
import timeit
# 测量代码片段执行时间
code = """
result = sum(range(1000))
"""
time = timeit.timeit(code, number=10000)
print(f"执行时间: {time:.4f}秒")
# 比较不同实现
time1 = timeit.timeit('"-".join(str(i) for i in range(100))', number=10000)
time2 = timeit.timeit('"-".join([str(i) for i in range(100)])', number=10000)
time3 = timeit.timeit('"-".join(map(str, range(100)))', number=10000)
print(f"生成器: {time1:.4f}秒")
print(f"列表推导: {time2:.4f}秒")
print(f"map: {time3:.4f}秒")
1.2 使用cProfile进行性能分析
import cProfile
import pstats
def slow_function():
total = 0
for i in range(1000000):
total += i
return total
# 分析函数性能
cProfile.run('slow_function()', 'profile_stats')
# 查看统计信息
stats = pstats.Stats('profile_stats')
stats.sort_stats('cumulative')
stats.print_stats(10)
1.3 使用line_profiler逐行分析
# 安装: pip install line_profiler
# 使用装饰器标记要分析的函数
@profile
def function_to_profile():
a = [i for i in range(10000)]
b = [i**2 for i in a]
return sum(b)
# 运行: kernprof -l -v script.py
二、数据结构选择
选择合适的数据结构对性能影响巨大。
2.1 列表 vs 集合
# 检查元素是否存在
import time
# 列表(O(n))
large_list = list(range(10000))
start = time.time()
9999 in large_list
print(f"列表查找: {time.time() - start:.6f}秒")
# 集合(O(1))
large_set = set(range(10000))
start = time.time()
9999 in large_set
print(f"集合查找: {time.time() - start:.6f}秒")
2.2 列表 vs 双端队列
from collections import deque
# 列表在头部插入很慢(O(n))
lst = []
for i in range(10000):
lst.insert(0, i)
# 双端队列在头部插入很快(O(1))
dq = deque()
for i in range(10000):
dq.appendleft(i)
2.3 字典 vs defaultdict
from collections import defaultdict
# 普通字典
word_count = {}
for word in ['apple', 'banana', 'apple']:
if word not in word_count:
word_count[word] = 0
word_count[word] += 1
# defaultdict更简洁高效
word_count = defaultdict(int)
for word in ['apple', 'banana', 'apple']:
word_count[word] += 1
三、避免不必要的计算
3.1 缓存计算结果
from functools import lru_cache
# 不使用缓存
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 使用缓存
@lru_cache(maxsize=None)
def fibonacci_cached(n):
if n < 2:
return n
return fibonacci_cached(n-1) + fibonacci_cached(n-2)
# fibonacci(35) 很慢
# fibonacci_cached(35) 很快
3.2 避免重复计算
# 低效
def process_data(data):
for item in data:
if len(data) > 100: # 每次都计算len(data)
process_large(item)
# 高效
def process_data(data):
data_len = len(data) # 只计算一次
for item in data:
if data_len > 100:
process_large(item)
四、字符串操作优化
4.1 字符串拼接
# 低效:使用+拼接
result = ""
for i in range(10000):
result += str(i)
# 高效:使用join
result = "".join(str(i) for i in range(10000))
# 高效:使用列表累积
parts = []
for i in range(10000):
parts.append(str(i))
result = "".join(parts)
4.2 字符串格式化
name = "Alice"
age = 30
# 较慢
s1 = "Name: %s, Age: %d" % (name, age)
# 较快
s2 = "Name: {}, Age: {}".format(name, age)
# 最快
s3 = f"Name: {name}, Age: {age}"
五、列表推导式 vs 循环
# 循环
squares = []
for i in range(1000):
squares.append(i**2)
# 列表推导式(更快)
squares = [i**2 for i in range(1000)]
# 生成器表达式(内存效率更高)
squares = (i**2 for i in range(1000))
六、使用内置函数和库
内置函数通常用C实现,比纯Python代码快得多。
# 慢
def my_sum(numbers):
total = 0
for num in numbers:
total += num
return total
# 快
total = sum(numbers)
# 慢
def my_max(numbers):
maximum = numbers[0]
for num in numbers[1:]:
if num > maximum:
maximum = num
return maximum
# 快
maximum = max(numbers)
七、局部变量优化
# 全局变量访问较慢
import math
def calculate_slow():
result = 0
for i in range(100000):
result += math.sqrt(i)
return result
# 局部变量访问更快
def calculate_fast():
result = 0
sqrt = math.sqrt # 缓存为局部变量
for i in range(100000):
result += sqrt(i)
return result
八、使用生成器节省内存
# 占用大量内存
def read_large_file(filename):
with open(filename) as f:
return f.readlines()
# 内存高效
def read_large_file_gen(filename):
with open(filename) as f:
for line in f:
yield line.strip()
九、使用NumPy加速数值计算
import numpy as np
# 纯Python(慢)
def python_sum():
data = list(range(1000000))
return sum([x**2 for x in data])
# NumPy(快)
def numpy_sum():
data = np.arange(1000000)
return np.sum(data**2)
十、并行处理
10.1 使用多进程处理CPU密集型任务
from multiprocessing import Pool
def cpu_intensive_task(n):
return sum(i**2 for i in range(n))
# 串行
results = [cpu_intensive_task(1000000) for _ in range(4)]
# 并行
with Pool(4) as pool:
results = pool.map(cpu_intensive_task, [1000000] * 4)
10.2 使用多线程处理I/O密集型任务
from concurrent.futures import ThreadPoolExecutor
import requests
def fetch_url(url):
return requests.get(url).text
urls = ['https://example.com'] * 10
# 串行
results = [fetch_url(url) for url in urls]
# 并行
with ThreadPoolExecutor(max_workers=5) as executor:
results = list(executor.map(fetch_url, urls))
十一、使用__slots__减少内存占用
# 普通类
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# 使用__slots__
class PointSlots:
__slots__ = ['x', 'y']
def __init__(self, x, y):
self.x = x
self.y = y
# PointSlots实例占用更少内存
十二、避免不必要的对象创建
# 低效
def process_items(items):
for item in items:
temp_list = [] # 每次循环都创建新列表
temp_list.append(item)
process(temp_list)
# 高效
def process_items(items):
temp_list = [] # 只创建一次
for item in items:
temp_list.clear()
temp_list.append(item)
process(temp_list)
十三、使用适当的算法
# O(n²) 冒泡排序
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
# O(n log n) 内置排序
arr.sort() # 或 sorted(arr)
十四、延迟导入
# 在模块顶部导入所有内容可能很慢
import heavy_module
def rarely_used_function():
# 只在需要时导入
import heavy_module
return heavy_module.do_something()
十五、使用Cython加速
# 安装: pip install cython
# 创建 .pyx 文件
# example.pyx
def fibonacci(int n):
cdef int a = 0, b = 1, i
for i in range(n):
a, b = b, a + b
return a
# 编译后速度显著提升
十六、数据库查询优化
# 低效:N+1查询问题
users = User.query.all()
for user in users:
print(user.profile.bio) # 每次都查询数据库
# 高效:使用join预加载
users = User.query.join(Profile).all()
for user in users:
print(user.profile.bio) # 不需要额外查询
十七、性能优化的黄金法则
1. 先测量,再优化(不要过早优化)
2. 优化瓶颈,而不是整个代码
3. 选择合适的数据结构和算法
4. 使用内置函数和标准库
5. 考虑使用C扩展或Cython
6. 权衡时间复杂度和空间复杂度
7. 编写可读的代码,然后优化关键部分
十八、总结
Python性能优化是一个系统工程,需要从算法、数据结构、语言特性等多个角度考虑。关键是先通过性能分析工具找出瓶颈,然后针对性地优化。记住,可读性和可维护性同样重要,不要为了微小的性能提升而牺牲代码质量。
Python性能优化技巧