|
|
@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
## 用 cProfile 找出代码中的性能瓶颈并进行改进
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 背景介绍
|
|
|
|
|
|
|
|
在编写和优化 Python 程序的过程中,性能问题是一个不可忽视的环节。程序的性能瓶颈可能隐藏在大量的函数调用和代码执行过程中,尤其是在处理大量数据或进行复杂计算时,性能问题可能会严重影响程序的执行效率。为了找到并解决这些性能瓶颈,性能分析工具如 cProfile 就显得尤为重要。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 2. cProfile 简介
|
|
|
|
|
|
|
|
cProfile 是 Python 内置的性能分析模块,它能够跟踪每个函数的调用情况,记录函数的执行次数和消耗的时间,从而帮助开发者找到代码中的性能瓶颈。cProfile 的优点在于它是标准库的一部分,无需额外安装,且使用简单,功能强大。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 使用 cProfile 进行性能分析
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 3.1 代码示例
|
|
|
|
|
|
|
|
为了使用 cProfile 进行性能分析,我们可以在项目的主文件中加入以下代码:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
import cProfile
|
|
|
|
|
|
|
|
import pstats
|
|
|
|
|
|
|
|
import a_wordcloud
|
|
|
|
|
|
|
|
import bvid
|
|
|
|
|
|
|
|
import to_allexcel
|
|
|
|
|
|
|
|
import to_danmu
|
|
|
|
|
|
|
|
import to_excel
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_all():
|
|
|
|
|
|
|
|
# 在这里调用你希望运行和分析的函数
|
|
|
|
|
|
|
|
a_wordcloud.main()
|
|
|
|
|
|
|
|
bvid.main()
|
|
|
|
|
|
|
|
to_allexcel.main()
|
|
|
|
|
|
|
|
to_danmu.main()
|
|
|
|
|
|
|
|
to_excel.main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
|
|
profiler = cProfile.Profile()
|
|
|
|
|
|
|
|
profiler.enable()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
run_all()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
profiler.disable()
|
|
|
|
|
|
|
|
profiler.dump_stats('performance_profile.prof')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 分析结果
|
|
|
|
|
|
|
|
with open('performance_report.txt', 'w') as f:
|
|
|
|
|
|
|
|
ps = pstats.Stats(profiler, stream=f)
|
|
|
|
|
|
|
|
ps.sort_stats('cumulative')
|
|
|
|
|
|
|
|
ps.print_stats()
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 3.2 运行性能分析
|
|
|
|
|
|
|
|
在将上述代码添加到项目中之后,运行程序,程序执行结束后会生成两个文件:
|
|
|
|
|
|
|
|
- `performance_profile.prof`:保存性能分析数据的二进制文件。
|
|
|
|
|
|
|
|
- `performance_report.txt`:包含详细的性能分析报告,包括各个函数的调用次数和执行时间等。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 性能数据的查看与分析
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 4.1 打开 `performance_report.txt`
|
|
|
|
|
|
|
|
打开生成的 `performance_report.txt` 文件,可以看到各个函数的调用次数(ncalls)、总耗时(tottime)、自耗时(percall)、以及累计耗时(cumtime)等信息。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例如:
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
5001 2.180 0.000 2.180 0.000 {built-in method time.sleep}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- `ncalls`: 函数被调用的次数。
|
|
|
|
|
|
|
|
- `tottime`: 函数本身消耗的时间,不包括调用其他函数的时间。
|
|
|
|
|
|
|
|
- `percall`: `tottime`/`ncalls`,即每次调用的平均耗时。
|
|
|
|
|
|
|
|
- `cumtime`: 函数及其调用的所有子函数的总耗时。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 4.2 性能瓶颈的分析
|
|
|
|
|
|
|
|
通过阅读 `performance_report.txt`,可以轻松地找到消耗时间最多的函数。例如,如果某个函数的 `tottime` 非常高,而该函数又频繁调用,那么它很可能就是程序的性能瓶颈。其中代码程序在获取bvid号时消耗时间较高,这主要是因为我的代码是采用顺序执行的方式,即需要爬取完一个视频之后才能继续爬取其他视频。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 优化方法和结果:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
因此我改进的思路是采用多进程并发执行,从而提升运行时间。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
以下是前后对比:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
![image-20240918025811934](C:\Users\onelastkiss\AppData\Roaming\Typora\typora-user-images\image-20240918025811934.png)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
![image-20240918025828605](C:\Users\onelastkiss\AppData\Roaming\Typora\typora-user-images\image-20240918025828605.png)
|