I/O密集型任务、计算密集型任务,以及Gil锁机制
目录
为什么计算密集型用多进程,I/O密集型用多线程
首先记住一点,多进程的资源消耗是远大于线程的
- 大量的I/O等待期间CPU都是空闲状态,因此对资源的利用率非常低,俗称占着茅坑不拉屎,因此开辟线程更加充分利用资源,也不会因为有大型的计算导致内存崩溃
- 计算密集型对CPU的运算能力要求较高,通常不是单线程能满足的,因此需要整个进程为其进行处理
当然以上都是基于cpython的,因为python有gil锁的缘故,所以才会有多进程的概念,实际上在正常情况下多进程有明显的资源浪费问题,多线程在效率和资源利用率上明显优于多进程
Gil锁机制(Global Interpreter Lock)
GIL锁是CPython解释器中的一个互斥锁,也叫全局解释器锁,用于防止多个线程同时执行Python字节码。保证同一进程下只有一个线程能够执行Python代码,并操作Python对象
为什么要有Gil锁?
- 多线程会被垃圾回收影响,比如线程1刚取消一个对象的引用,但是线程2也要对该对象进行调用,但是就在线程2调用该对象的前一刻被引用计数标记为0,那么就会出现数据安全问题
- 当年只有单核cpu,即使开了多线程也只有一个线程在运行,因此作者强加了gil锁
影响
- CPU密集型任务受限:对于CPU密集型任务,由于GIL的存在,多线程并不能有效地提高性能,因为多个线程无法同时执行Python字节码
- IO密集型任务相对不受限:在IO密集型任务中,线程在等待IO时会释放GIL,允许其他线程执行Python字节码,因此在这种情况下,多线程能够发挥一定作用
示例
CPU密集型任务
当使用ThreadPoolExecutor
运行脚本时,即使开了多线程也不会达到预期的执行效率,因为Gil锁在同一时间段内只允许单线程运算,因此在python中使用多线程执行CPU密集型任务时多半是无效的,反之多进程不受影响
假如一个计算密集型的任务需要 10s 的执行时间,总共有4个这样的任务
多进程: 需要开启 4 个进程,但是 4 个 CPU 并行,最终只需要消耗 10s 多一点的时间。
多线程: 只需要开1 个进程,这个进程开启 4 个线程,开启线程所消耗的资源很少,但是由于最终执行是只有一个 CPU 可以工作,所以最终消耗 40s 多的时间。
I/O密集型
假如是多个 IO密集型 的任务 (例如input()
,time.sleep()
)CPU 大多数时间是处于闲置状态,频繁的切换
多进程: 进程进行切换需要消耗大量资源
多线程: 线程进行切换并不需要消耗大量资源,即使有GIL锁的存在,最终也会以量取胜多进程