#深入理解# Python的多进程与多线程

知识补充

想要学习多进程与多线程,首先要理解以下概念:

1. 并发与并行

一个cpu同时执行多个线程的过程叫做并发;虽然叫做并发,但在底层CPU每次只能执行一个线程,
具体方法是将cpu分成多个时间片段,然后让CPU以这些时间片段为最小单位轮流执行这些线程

多个cpu同时执行多个线程的过程叫做并行,并行才是真正的同时执行多个任务,如果主机只有一个CPU,那么就无法实现并行过程

说的通俗一些,并行与并发只是和cpu的使用数量相关;并发技术目的是增加单个CPU的运行效率,而并行技术的目的是通过增加CPU的核心数量进而增加整体的计算效率

2. CPU密集型与I/O密集型

2.1 CPU密集型(CPU bound)

CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。

2.2 IO密集型(I/O bound)

IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。

正文

1. 多进程与多线程的区别

  1. 一个进程内可以包含多个线程,一个线程只能属于一个进程
  2. 一个进程内所有线程共享同一片内存空间、共享一个cpu资源
  3. 多个进程之间的内存空间相互独立,相互之间不能够共享数据(多个进程可以通过某种方式用实现数据共享,但是成本较高)
  4. 根据2,3可知,进程是分配存储资源的基本单位,线程是分配CPU资源的基本单位

2. 多线程、多进程、CPU核心的关系

一般情况下,多线程主要有两种,一种是用户态多线程;一种是内核态多线程,两者的主要区别是能否支持多核下并行运行

  • 同一进程下的用户态多线程,只能在同一个CPU内核上进行计算
  • 同一进程下的内核态多线程(java1.2之后用内核级线程),在操作系统内核的支持下可以在多核下并行运行

这里要单独解释一下Python的多线程和多进程

由于 Python GIL(全局解释锁)的存在,使得 Python 同一个时刻只有一个线程在一个CPU内核上执行字节码,无法将多个线程映射到多个CPU内核上,即不能发挥多核CPU的优势;

换句话说,Python同一进程下的多个线程只能并发执行,不能并行执行,因此,Python多线程技术对于IO密集型任务的效率提升明显,但对于CPU密集型任务 Python多线程技术的效果较差

3. 多进程与多线程如何选择

3.1 一般情况

对于一般编程语言来说,线程和进程各自的优势如下:

对比维度多进程多线程总结
数据共享、同步数据共享复杂,需要用IPC;数据是分开的,同步简单因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂各有优势
内存、CPU占用内存多,切换复杂,CPU利用率低占用内存少,切换简单,CPU利用率高线程占优
创建销毁、切换创建销毁、切换复杂,速度慢创建销毁、切换简单,速度很快线程占优
编程、调试编程简单,调试简单编程复杂,调试复杂进程占优
可靠性进程间不会互相影响一个线程挂掉将导致整个进程挂掉进程占优
分布式适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单适应于多核分布式进程占优

3.2 Python语言下的选择

由于 Python GIL锁的存在,在Python中,对于同一进程中的多个线程并不能在多个CPU内核上并行执行,因此除了上述因素,在Python中还要考虑要处理的任务是否是CPU密集型任务

如果是CPU密集型任务,那么对于每个任务来说,CPU都满载状态,这时就需要使用多进程技术,将多个任务分配到多个CPU内核上进行执行(多进程下每个进程都有一个单独的GIL,因此多个进程可以同时执行多个线程)

如果是IO密集型任务,CPU在很多时候属于闲置状态,那么就可以使用多线程技术给CPU分配更多的线程,从而增加CPU的使用效率,

补充:

在Python中,对于CPU密集型任务,CPU核数越多,多线程(单进程)的效率反而会更低;
为了解释这个原因,我们先要了解 Python进行线程切换的过程:

  1. Pyhton解释器释放GIL锁
  2. 调用操作系统的线程调度模块,唤醒 N 个(N=CPU核心数)线程
  3. 一个线程获得GIL锁并执行,其他线程转为待调度状态

过程2解读: 这里操作系统的线程调度模块和Python内部的GIL锁没有关系,需要分开来看;正常情况下操作系统认为多个CPU核心可以并行执行多个线程,因此当调用操作系统的线程调度模块时,操作系统会为每个CPU核心唤醒一个线程,等待被调用

过程3解读: 虽然过程2唤醒了N个线程等待被调用,但是由于Python GIL的存在,每次也只有一个线程能够获得GIL锁并执行;唤醒每个线程是要消耗资源的,核心越多每次GIL释放后系统唤醒的线程数量也会越多,Python中只有一个线程能够最终被执行,那么唤醒多个线程必然会浪费资源,这其实是Python多核多线程效率低的根本原因。

参考文章:

  1. 熬了两个通宵写的!终于把多线程和多进程彻底讲明白了!
  2. Python的GIL机制与多线程编程
  3. 谈谈python的GIL、多线程、多进程
  4. python GIL 全局锁,多核cpu下的多线程性能究竟如何?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

energy_百分百

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值