面试题答案
一键面试使用line_profiler找出性能瓶颈所在具体行
- 安装line_profiler:可以使用
pip install line_profiler
进行安装。 - 编写装饰器使用代码:
- 在模块代码中,在需要分析的函数定义上方添加
@profile
装饰器。例如,假设模块名为your_module.py
,函数定义如下:
@profile def your_function(): # 函数具体代码,这里面有循环、条件判断等复杂逻辑 pass
- 如果类中的方法需要分析,也在方法定义上方添加
@profile
装饰器。
class YourClass: @profile def your_method(self): # 方法具体代码 pass
- 在模块代码中,在需要分析的函数定义上方添加
- 运行分析:通过命令行运行
kernprof -l -v your_module.py
,-l
表示使用line_profiler,-v
表示输出详细的分析结果。运行后会输出每行代码的执行次数、耗时等信息,通过这些信息可以找出性能瓶颈所在的具体行。
优化高耗时行代码
- 算法优化:
- 如果高耗时行在循环中,检查循环算法。例如,若使用简单的嵌套循环进行查找,可以考虑使用更高效的数据结构(如哈希表)来降低时间复杂度。比如,将列表查找改为字典查找,字典的查找时间复杂度平均为O(1),而列表查找的时间复杂度为O(n)。
# 假设原来使用列表查找 my_list = [1, 2, 3, 4, 5] target = 3 for num in my_list: if num == target: print('找到目标') # 优化为字典查找 my_dict = {1: None, 2: None, 3: None, 4: None, 5: None} if target in my_dict: print('找到目标')
- 减少不必要计算:
- 如果高耗时行存在重复计算,将计算结果缓存起来。例如,在一个循环中多次计算相同的复杂表达式,可以在循环外先计算一次并保存结果。
# 原来在循环中重复计算 for i in range(1000): result = complex_calculation(i) # 其他操作 # 优化为缓存计算结果 cache = {} for i in range(1000): if i not in cache: cache[i] = complex_calculation(i) result = cache[i] # 其他操作
- 使用更高效的库:
- 例如,对于数值计算,如果原来使用Python原生的列表操作,可以考虑使用
numpy
库。numpy
库是用C语言实现的,执行效率更高。
# 原生Python列表计算 my_list = [1, 2, 3, 4, 5] new_list = [] for num in my_list: new_list.append(num * 2) # 使用numpy优化 import numpy as np my_array = np.array([1, 2, 3, 4, 5]) new_array = my_array * 2
- 例如,对于数值计算,如果原来使用Python原生的列表操作,可以考虑使用
- 避免全局变量:访问全局变量相对较慢,如果高耗时行频繁访问全局变量,可以尝试将其作为函数参数传递,使变量变为局部变量,提高访问速度。
GLOBAL_VARIABLE = 10 # 原来频繁访问全局变量 def your_function(): result = GLOBAL_VARIABLE * 2 return result # 优化为局部变量 def your_function(new_variable): result = new_variable * 2 return result result = your_function(10)