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

8 months ago
8 months ago
# 目标
本节使用一个爬虫任务和计算任务来展示如何追求代码的性能 。
充分理解线程、协程、进程、同步、异步、阻塞、非阻塞等概念,并能够根据具体场景选择合适的并发模型。
主线问题如何解决IO和计算速度不匹配、如何任务分解、分发和协作 。
8 months ago
# 任务
## 1、CPU密集型/计算密集型:
  将```sum(i * i for i in range(10**8))```作为一个子任务运行5次分别使用单线程、多线程、多进程、多协程、异步等方式并对比运行时间、内存使用、CPU使用等指标。
8 months ago
## 2、IO密集型
8 months ago
# 讨论分析
## 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>