You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 目标
本节使用一个爬虫任务和计算任务来展示如何追求代码的性能 。
充分理解线程、协程、进程、同步、异步、阻塞、非阻塞等概念,并能够根据具体场景选择合适的并发模型。
主线问题如何解决IO和计算速度不匹配、如何任务分解、分发和协作 。
# 任务
## 1、CPU密集型/计算密集型:
  将```sum(i * i for i in range(10**8))```作为一个子任务运行5次分别使用单线程、多线程、多进程、多协程、异步等方式并对比运行时间、内存使用、CPU使用等指标。
## 2、IO密集型
# 讨论分析
## 1、CPU密集型/计算密集型:
  为控制变量代码在同一台设备上运行且关闭其他进程保证CPU资源不被其他进程占用。测试结果如下
### 普通做法:
#### 运行前:
  CPU使用率0.0%内存使用率53.3%
#### 运行后:
  CPU使用率0.6%内存使用率53.0%内存使用0.003336MB峰值内存使用0.004216MB单个子任务运行平均时间7.86s总运行时间39.31s
#### 运行结束30秒后
  CPU使用率0.6%内存使用率53.0%
### 多进程:
#### 运行前:
  CPU使用率0.0%内存使用率52.8%
#### 运行后:
  CPU使用率1.3%内存使用率52.9%内存使用0.096089MB峰值内存使用0.121865MB单个子任务运行平均时间0.654s总运行时间1.86s
#### 运行结束30秒后
  CPU使用率0.6%内存使用率52.7%
### 多线程:
#### 运行前:
  CPU使用率3.8%内存使用率53.1%
#### 运行后:
  CPU使用率3.6%内存使用率53.1%内存使用0.001472MB峰值内存使用0.019296MB单个子任务运行平均时间38.89s总运行时间39.77s
#### 运行结束30秒后
  CPU使用率0.7%内存使用率52.9%
### 多线程 + 线程池:
#### 运行前:
  CPU使用率0.0%内存使用率52.9%
#### 运行后:
  CPU使用率0.7%内存使用率53.1%内存使用0.000952MB峰值内存使用0.036604MB单个子任务运行平均时间40.49s总运行时间41.16s
#### 运行结束30秒后
  CPU使用率0.6%内存使用率52.9%
### 多协程:
#### 运行前:
  CPU使用率1.1%内存使用率53.4%
#### 运行后:
  CPU使用率0.2%内存使用率53.4%内存使用0.009448MB峰值内存使用0.011027MB单个子任务运行平均时间9.14s总运行时间45.70s
#### 运行结束30秒后
  CPU使用率0.6%内存使用率53.4%
### 多进程 + 异步:
#### 运行前:
  CPU使用率0.8%内存使用率54.9%
#### 运行后:
  CPU使用率0.6%内存使用率54.9%内存使用0.123481MB峰值内存使用0.188774MB单个子任务运行平均时间0.63s总运行时间1.85s
#### 运行结束30秒后
  CPU使用率0.9%内存使用率55.0%
## 2、IO密集型
  为控制变量,代码在同一台设备上运行,关闭其他进程,并在相同的网络环境下运行,保证网络资源不被其他进程占用。
### 普通做法:
#### 运行前:
  CPU使用率0.0%内存使用率52.5%
#### 运行后:
  CPU使用率0.9%内存使用率52.6%内存使用0.074968MB峰值内存使用4.162339MB总运行时间5.56s
#### 运行结束30秒后
  CPU使用率0.6%内存使用率52.5%
### 多进程:
#### 运行前:
  CPU使用率0.0%内存使用率52.7%
#### 运行后:
  CPU使用率5.0%内存使用率52.8%内存使用0.03219MB峰值内存使用0.085236MB总运行时间5.81s
#### 运行结束30秒后
  CPU使用率1.2%内存使用率53.1%
### 多线程:
#### 运行前:
  CPU使用率0.0%内存使用率52.9%
#### 运行后:
  CPU使用率0.1%内存使用率53.0%内存使用MB峰值内存使用MB总运行时间1.63s
#### 运行结束30秒后
  CPU使用率0.5%内存使用率52.9%
### 多线程 + 线程池:
#### 运行前:
  CPU使用率1.3%内存使用率53.2%
#### 运行后:
  CPU使用率1.3%内存使用率53.1%内存使用0.092493MB峰值内存使用4.371028MB总运行时间1.47s
#### 运行结束30秒后
  CPU使用率0.8%内存使用率53.2%
### 多协程:
#### 运行前:
  CPU使用率1.1%内存使用率54.4%
#### 运行后:
  CPU使用率0.8%内存使用率54.4%内存使用0.753684MB峰值内存使用15.09151MB总运行时间1.45s
#### 运行结束30秒后
  CPU使用率0.8%内存使用率54.4%
### 多进程 + 异步:
#### 运行前:
  CPU使用率1.5%内存使用率60.0%
#### 运行后:
  CPU使用率0.8%内存使用率59.8%内存使用0.569592MB峰值内存使用6.360097MB总运行时间7.40s
#### 运行结束30秒后
  CPU使用率1.3%内存使用率59.6%
# 总结
## 1、CPU密集型/计算密集型:
| | 普通做法 | 多进程 | 多线程 | 多线程+线程池 | 多协程 | 多进程+异步 |
| :----------------------: | :--------: | :--------: | :--------: | :-----------: | :--------: | :---------: |
| 运行前CPU使用率 | 0.0% | 0.0% | 3.8% | 0.0% | 1.1% | 0.8% |
| 运行后CPU使用率 | 0.6% | 1.3% | 3.6% | 0.7% | 0.2% | 0.6% |
| 运行结束30秒后CPU使用率 | 0.6% | 0.6% | 0.7% | 0.6% | 0.6% | 0.9% |
| 运行前内存使用率 | 53.3% | 52.8% | 53.1% | 52.9% | 53.4% | 54.9% |
| 运行后内存使用率 | 53.0% | 52.9% | 53.1% | 53.1% | 53.4% | 54.9% |
| 运行结束30秒后内存使用率 | 53.0% | 52.7% | 52.9% | 52.9% | 53.4% | 55.0% |
| 内存使用 | 0.003336MB | 0.096089MB | 0.001472MB | 0.000952MB | 0.009448MB | 0.123481MB |
| 峰值内存使用 | 0.004216MB | 0.121865MB | 0.019296MB | 0.036604MB | 0.011027MB | 0.188774MB |
| 单个子任务运行平均时间 | 7.86s | 0.654s | 38.89s | 40.49s | 9.14s | 0.63s |
| 总运行时间 | 39.31s | 1.86s | 39.77s | 41.16s | 45.70s | 1.85s |
  根据表格中的数据,我们可以对不同的并发和并行编程方法进行详细的总结:
### 普通做法
- **CPU使用率**在任务运行前、运行后和运行结束30秒后的CPU使用率都较低表明普通做法没有充分利用CPU资源。
- **内存使用率**:内存使用率变化不大,表明普通做法对内存的影响较小。
- **内存使用**:内存使用量和峰值内存使用量都很低。
- **运行时间**:单个子任务和总任务的运行时间都较长,表明普通做法效率较低。
### 多进程
- **CPU使用率**在任务运行后CPU使用率显著增加表明多进程方法能够充分利用多核CPU的优势。
- **内存使用率**:内存使用率略有增加,但变化不大。
- **内存使用**:内存使用量和峰值内存使用量较高,表明多进程方法对内存的需求较大。
- **运行时间**单个子任务和总任务的运行时间都显著减少表明多进程方法在处理CPU密集型任务时效率最高。
### 多线程
- **CPU使用率**在任务运行前、运行后和运行结束30秒后的CPU使用率都较低表明多线程方法没有充分利用CPU资源。
- **内存使用率**:内存使用率变化不大。
- **内存使用**:内存使用量和峰值内存使用量较低。
- **运行时间**单个子任务和总任务的运行时间都较长表明多线程方法在处理CPU密集型任务时效率较低。
### 多线程+线程池
- **CPU使用率**在任务运行后CPU使用率略有增加但变化不大。
- **内存使用率**:内存使用率变化不大。
- **内存使用**:内存使用量和峰值内存使用量较低。
- **运行时间**:单个子任务和总任务的运行时间都较长,表明多线程+线程池方法在处理CPU密集型任务时效率较低。
### 多协程
- **CPU使用率**在任务运行前、运行后和运行结束30秒后的CPU使用率都较低表明多协程方法没有充分利用CPU资源。
- **内存使用率**:内存使用率变化不大。
- **内存使用**:内存使用量和峰值内存使用量较低。
- **运行时间**单个子任务和总任务的运行时间都较长表明多协程方法在处理CPU密集型任务时效率较低。
### 多进程+异步
- **CPU使用率**在任务运行后CPU使用率显著增加表明多进程+异步方法能够充分利用多核CPU的优势。
- **内存使用率**:内存使用率略有增加,但变化不大。
- **内存使用**:内存使用量和峰值内存使用量较高,表明多进程+异步方法对内存的需求较大。
- **运行时间**:单个子任务和总任务的运行时间都显著减少,表明多进程+异步方法在处理CPU密集型任务时效率最高。
### 结论
- **多进程**和**多进程+异步**方法在处理CPU密集型任务时效率最高能够充分利用多核CPU的优势但对内存的需求较大。
- **多线程**和**多线程+线程池**方法在处理CPU密集型任务时效率较低主要是由于Python的全局解释器锁GIL的存在无法实现真正的并行。
- **多协程**方法在处理CPU密集型任务时效率较低但在处理I/O密集型任务时可能会有更好的表现。
- **普通做法**效率最低,无法充分利用系统资源。
## 2、IO密集型
| | 普通做法 | 多进程 | 多线程 | 多线程+线程池 | 多协程 | 多进程+异步 |
| :----------------------: | :--------: | :--------: | :----: | :-----------: | :--------: | :---------: |
| 运行前CPU使用率 | 0.0% | 0.0% | 0.0% | 1.3% | 1.1% | 1.5% |
| 运行后CPU使用率 | 0.9% | 5.0% | 0.1% | 1.3% | 0.8% | 0.8% |
| 运行结束30秒后CPU使用率 | 0.6% | 1.2% | 0.5% | 0.8% | 0.8% | 1.3% |
| 运行前内存使用率 | 52.5% | 52.7% | 52.9% | 53.2% | 54.4% | 60.0% |
| 运行后内存使用率 | 52.6% | 52.8% | 53.0% | 53.1% | 54.4% | 59.8% |
| 运行结束30秒后内存使用率 | 52.5% | 53.1% | 52.9% | 53.2% | 54.4% | 59.6% |
| 内存使用 | 0.074968MB | 0.03219MB | N/A | 0.092493MB | 0.753684MB | 0.569592MB |
| 峰值内存使用 | 4.162339MB | 0.085236MB | N/A | 4.371028MB | 15.09151MB | 6.360097MB |
| 总运行时间 | 5.56s | 5.81s | 1.63s | 1.47s | 1.45s | 7.40s |
  根据表格中的数据,我们可以对不同的并发和并行编程方法进行详细的总结:
### 普通做法
- **CPU使用率**在任务运行前、运行后和运行结束30秒后的CPU使用率都较低表明普通做法没有充分利用CPU资源。
- **内存使用率**:内存使用率变化不大,表明普通做法对内存的影响较小。
- **内存使用**:内存使用量和峰值内存使用量都很低。
- **运行时间**总运行时间为5.56秒,表明普通做法效率较低。
### 多进程
- **CPU使用率**在任务运行后CPU使用率显著增加表明多进程方法能够充分利用多核CPU的优势。
- **内存使用率**:内存使用率略有增加,但变化不大。
- **内存使用**:内存使用量和峰值内存使用量较低。
- **运行时间**总运行时间为5.81秒略高于普通做法表明多进程方法在处理IO密集型任务时效率较高。
### 多线程
- **CPU使用率**在任务运行前、运行后和运行结束30秒后的CPU使用率都较低表明多线程方法没有充分利用CPU资源。
- **内存使用率**:内存使用率变化不大。
- **内存使用**:内存使用量和峰值内存使用量较低。
- **运行时间**总运行时间为1.63秒显著低于普通做法表明多线程方法在处理IO密集型任务时效率较高。
### 多线程+线程池
- **CPU使用率**在任务运行后CPU使用率略有增加但变化不大。
- **内存使用率**:内存使用率变化不大。
- **内存使用**:内存使用量和峰值内存使用量较低。
- **运行时间**总运行时间为1.47秒,显著低于普通做法,表明多线程+线程池方法在处理IO密集型任务时效率较高。
### 多协程
- **CPU使用率**在任务运行前、运行后和运行结束30秒后的CPU使用率都较低表明多协程方法没有充分利用CPU资源。
- **内存使用率**:内存使用率变化不大。
- **内存使用**:内存使用量和峰值内存使用量较高。
- **运行时间**总运行时间为1.45秒显著低于普通做法表明多协程方法在处理IO密集型任务时效率较高。
### 多进程+异步
- **CPU使用率**在任务运行后CPU使用率显著增加表明多进程+异步方法能够充分利用多核CPU的优势。
- **内存使用率**:内存使用率略有增加,但变化不大。
- **内存使用**:内存使用量和峰值内存使用量较高。
- **运行时间**总运行时间为7.40秒,略高于普通做法,表明多进程+异步方法在处理IO密集型任务时效率较低。
### 结论
- **多线程**、**多线程+线程池**和**多协程**方法在处理IO密集型任务时效率最高能够显著减少总运行时间。
- **多进程**方法在处理IO密集型任务时效率较高但略低于多线程和多协程方法。
- **多进程+异步**方法在处理IO密集型任务时效率较低总运行时间较长。
- **普通做法**效率最低,无法充分利用系统资源。
<style>
h1{font:20pt "SimHei", sans-serif;}
h2{font:16pt "SimHei", sans-serif;}
p{font:12pt "SimSun", sans-serif;line-height:150%}
li{font:12pt "SimSun", sans-serif;line-height:150%}
</style>