一文讲透“进程、线程、协程”( 四 )
无论是单核还是多核,一个进程永远只能同时执行一个线程(拿到 GIL 的线程才能执行 , 如下图所示) , 这就是为什么在多核CPU上 , Python 的多线程效率并不高的根本原因 。
文章插图
那是不是在Python中遇到并发的需求就使用多进程就万事大吉了呢?其实不然 , 软件工程中有一句名言:没有银弹!
何时用?常见的应用场景不外乎三种:
- CPU密集型:程序需要占用CPU进行大量的运算和数据处理;
- I/O密集型:程序中需要频繁的进行I/O操作;例如网络中socket数据传输和读取等;
- CPU密集+I/O密集:以上两种的结合
下面主要解释一下I/O密集型的情况 。 与I/O设备交互 , 目前最常用的解决方案就是DMA 。
什么是DMADMA(Direct Memory Access)是系统中的一个特殊设备 , 它可以协调完成内存到设备间的数据传输 , 中间过程不需要CPU介入 。
以文件写入为例:
- 进程p1发出数据写入磁盘文件的请求
- CPU处理写入请求 , 通过编程告诉DMA引擎数据在内存的位置 , 要写入数据的大小以及目标设备等信息
- CPU处理其他进程p2的请求 , DMA负责将内存数据写入到设备中
- DMA完成数据传输 , 中断CPU
- CPU从p2上下文切换到p1,继续执行p1
文章插图
Python多线程的表现(I/O密集型)
- 线程Thread0首先执行 , 线程Thread1等待(GIL的存在)
- Thread0收到I/O请求 , 将请求转发给DMA,DMA执行请求
- Thread1占用CPU资源 , 继续执行
- CPU收到DMA的中断请求 , 切换到Thread0继续执行
文章插图
与进程的执行模式相似 , 弥补了GIL带来的不足 , 又由于线程的开销远远小于进程的开销 , 因此 , 在IO密集型场景中 , 多线程的性能更高
实践是检验真理的唯一标准 , 下面将针对I/O密集型场景进行测试 。
测试
- 执行代码
import multiprocessing
import threading
import time
def count(num):
time.sleep(1) ## 模拟IO操作
print("Process {0} End".format(num))
if __name__ == '__main__':
start_time = time.time
process = list
for i in range(5):
p = multiprocessing.Process(target=count, args=(i,))
# p = threading.Thread(target=count, args=(i,))
process.append(p)
for p in process:
p.start
for p in process:
p.join
end_time = time.time
print("Total time:{0}".format(end_time - start_time))
- 结果
## 多进程
Process 0 End
Process 3 End
Process 4 End
Process 2 End
Process 1 End
Total time:1.383193016052246
## 多线程
Process 0 End
Process 4 End
Process 3 End
Process 1 End
Process 2 End
- 一文看懂三星Galaxy S21系列发布会所有亮点
- 主板|主板名字带WiFi和不带有什么区别?一文读懂
- 微软发布新版Sysinternals组件Sysmon 13 可用于恶意软件进程篡改检测
- 一文读懂,书架箱和落地箱到底哪个好?
- 10nm进程受阻,芯片狂人梁孟松出走,中芯国际如何突破困境?
- 录音笔|科技解放生产力 录音笔的智能化进程
- 关闭一个进程 AMD锐龙CPU降温22.5℃
- 有史以来最大升级?一文看懂OriginOS带来的改变
- 超大杯来了!一文看懂OPPO Reno5 Pro+最大升级
- 简单一文教你制作多语言的Qlik Sense应用程序