python 之 进程与线程区别、GIL锁产生背景及对Python性能的影响?python的多线程是假的,为啥还用多线程

news/2024/11/17 10:30:40/

一、进程与线程区别

  • 根本区别
    进程是操作系统资源分配和调度的基本单位。每个进程都有自己独立的地址空间、数据、堆栈和状态
    线程操作系统调度的基本单位。一个进程可以有多个线程,这些线程共享进程的地址空间和资源
  • 资源开销(内存分配)
    进程创建新的进程需要分配独立的地址空间,有较大的字节。间进程切换和通信成本相对较高
    线程间共享地址空间和资源,因此线程的创建、切换和通信相对较接近,资源消耗较少
  • 通信方式
    进程间通信相对复杂,主要方式有管道、消息队列、信号量、共享内存等
    线程间通信更简单,可以直接访问其他线程的数据(因为它们共享地址空间),主要通过锁、信号量等同步原语来协调(也可以共享变量,共享内存,共享数据库,消息队列)
  • 隔离性与安全性:
    进程间有最大的隔离性,一个进程崩溃(例如访问了内存)一般不会影响其他进程。
    线程间共享进程资源,一个线程的错误可能影响同一进程的其他线程。
  • 使用场景
    IO密集型使用线程,计算密集型使用多进程
    进程适用于相互独立,需要较高安全性和隔离性的场景。
    线程适用于需要密集通信,或共享大量资源的场景,如服务器的请求处理
  • 补充
    协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。
    协程拥有自己的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

二、什么是GIL锁?GIL对Python性能的影响

  • GIL全局解释锁
    全局解释锁: 每个线程在执行过程的过程都需要先获取GIL,确保在同一时刻只有一个线程可以执行字节码,目的是简化CPython的设计, 保证线程安全

  • 线程释放GIL锁的情況:

    1. 在I0操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL
    2. Python 3.x使用计时器(执行时间达到國值后,当前线程释放GIL)或Python 2.x, tickets计t数达到100

    python使用多进程是可以利用多核的CPU资源的。
    多线程爬取比单线程性能有提升,因为遇到I0阻塞会自动释放GIL锁
    多进程适合在 CPU 密集型操作(Cpu 操作指令比较多,如位数多的浮点运算)。
    多线程适合在 IO 密集型操作(读写数据操作较多的,比如爬虫)

  • GIL全局解释锁:目的是简化CPython的设计, 保证线程安全

    1. 保护内存管理:
      GIL保证了对Python对象的访问是线程安全的。Python使用引用计数来管理内存,而更新引用计数并不是一个原子操作。假如两个线程同时修改同一个对象的引用计数,可能会导致引用计数被错误地更新,进而引发内存泄漏或错误地回收了仍在使用的对象。GIL确保了每一时刻只有一个线程在执行Python字节码,从而避免了这种竞争条件
    2. 简化设计和实现:
      通过使用GIL,CPython解释器的实现大大简化。GIL消除了多线程环境中复杂的锁管理和同步问题。没有GIL,CPython的每个数据结构都需要单独管理锁,这将增加设计和实现的复杂性

三、为啥python的多线程是假的,还用多线程

  • 为什么说Python的多线程是“假”的:
    GIL是一个全局锁,它保证一次只有一个线程执行Python字节码。在多核CPU环境中,这意味着Python的多线程不能有效利用多个CPU核心。相反,尽管有多个线程,但在任何给定的时刻,只有一个线程在执行。这使得Python的多线程对于计算密集型任务效果不佳,因为它们无法真正地执行任务。
  1. 为什么仍然使用Python的多线程
    对于I/O密集型任务(如网络通信、文件I/O等),多线程仍然是非常有效的。
    在I/O密集型任务中,线程大部分时间都在等待外部资源
    比如等待文件读取写完成或网络响应。在此期间,CPU几乎处于空闲状态。
    通过使用多线程,当一个线程等待I/O操作完成时,GIL可以被释放,其他线程可以继续执行。
    这样,多线程可以在I /O密集型应用中提高程序的总体性能和响应能力
  2. 综上所述
    尽管Python的多线程因GIL的存在而受到了一定的限制(特别是对于计算密集型任务),它仍然在某些场景下是有用和有效的。
    选择是否使用多线程,以及如何使用,取决于具体的应用场景和性能需求。

三、为啥 IO密集型使用线程,计算密集型使用多进程

3.1 I/O密集型任务:

I/O密集型任务是指系统的性能瓶颈主要出现在I/O操作上,如文件操作、网络通信等

为什么使用线程??

  1. I/O 密集型任务中,CPU 的使用并不是瓶颈,主要时间消耗在等待 I/O 操作上。在此期间,CPU 大部分时间都是空闲的。
  2. 线程的创建和思考成本很小,且所有线程共享进程的内存空间,使得线程之间的通信和数据交换成本很低。
  3. 使用线程可以使一个进程内的多个线程在等待I/O操作时可以共享同一个资源,这样当一个线程在等待I/O时,其他线程可以继续执行
3.2 计算密集型任务:

计算密集型任务是指系统的性能瓶颈主要出现在CPU计算上,即任务需要大量的CPU计算时间

为什么使用多进程??

  1. 对于计算密集型任务,多进程可以有效地利用多核CPU的优势,因为每个进程可以在一个单独的CPU核上执行。
    进程间的独立性较强,一个进程的崩溃不会影响到其他进程。
    在解释全局器锁(GIL)的存在的环境下(例如CPython),多线程程序无法有效利用多核CPU。GIL是Python的一个互斥锁,它阻止多个线程同时执行Python字节码。
    密集型任务,这可能导致程序的效率大幅度降低。多进程则参与GIL的限制,每个进程都有自己的GIL和独立的内存空间,因此可以充分利用多核CPU。

四、进程间8种通信方式详解

  1. 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常
    是指父子进程关系
  2. 消息队列通信:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载
    无格式字节流以及缓冲区大小受限等缺点
  3. 信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源
    时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  4. 信号:信号是种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
  5. 共享内存通信:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内
    存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实来实现进程间的同步和通信。
  6. socket:套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信
为什么爬虫使用多线程?而不是多进程
  • 多进程占用资源多,进程间通讯不方便,爬虫很少用
  • 多线程/协程 在请求数据和解析数据的时候采用多线程,大部分时间都是单线程爬虫,大部分情况采用分布式

什么是并发和并行?.同步和异步,阻塞和非阻塞的区别?

# 并发:同一时刻只能处理一个任务,但可以交替处理多个任务。(一个处理器同时处理多个任务〕
# 并行:同一时刻可以处理多个任务。(多个处理器或者是多核的处理器同时处理多个不同的任务)
# 类比:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。

线程是并发,进程是并行;进程之间相互独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。

阻塞:在执行一个操作时,不能做其他操作;
非阻塞:在执行一个操作时,能做其他操作。

阻塞和非阻塞关心的问题是:能不能做其他操作。


http://www.ppmy.cn/news/1043694.html

相关文章

实现Java异步调用的高效方法

文章目录 为什么需要异步调用?Java中的异步编程方式1. 使用多线程2. 使用Java异步框架 异步调用的关键细节结论 🎉欢迎来到Java学习路线专栏~实现Java异步调用的高效方法 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒🍹✨博客主页:IT陈寒的博…

堆外内存溢出排查记录

最近项目出现了占用RES过多的情况,通过jmap发现java堆栈 及 metaspace一切正常。那么就定位到时堆外内存了。 首先通过pmap -p pid ,发现当前进程有很多 64M的[anon]空间,初次定位为 内存碎片的问题。但是实际情况是很长一段时间后&#xff…

玄子Share - HTML Emmet 语法详细介绍

玄子Share - HTML Emmet 语法详细介绍 以下Emmet语法 基于WebStorm 2023.2演示 Emmet 语法介绍 Emmet 是一种缩写语法,旨在简化 HTML 和 CSS 的编写。它基于 CSS 选择器的语法结构,通过输入特定的缩写,可以快速生成 HTML 结构。 Emmet 语法…

改进YOLO系列:2.添加ShuffleAttention注意力机制

添加ShuffleAttention注意力机制 1. ShuffleAttention注意力机制论文2. ShuffleAttention注意力机制原理3. ShuffleAttention注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. ShuffleAttention注意力机制论文 论文题目:SA-NET: SHUFFLE ATTENTION …

Vue2.7.14、vuecli@5.0.8 升级 vite@4.4.8

项目背景 Vue2.7.14、vuecli5.0.8、element-ui2.15.13、node14.18.3 vite安装 pnpm add vite4.4.8 -D 入口文件index.html 文件位置修改 将pulic里的index.html移到根目录下 根目录/public/index.html 到 根目录/index.html 文件内容修改 <link rel"icon"…

stable diffusion 运行时报错: returned non-zero exit status 1.

运行sh run.sh安装stable diffusion时报错&#xff1a;ImportError: cannot import name builder from google.protobuf.internal (stable-diffusion-webui/venv/lib/python3.8/site-packages/google/protobuf/internal/__init__.py) 原因&#xff1a;python版本过低&#xff0…

all in one之安装pve(第一章)

第一章 安装PVE PVE安装 pverufusultraISO下载地址下载地址下载地址 因为我使用的是SD卡存储&#xff0c;尝试rufus安装失败&#xff0c;建议使用 ultraISO进行镜像写入。 U盘推荐4G往上。 下载pve 我下载的pve版本是7.4 ultraISO 把镜像写入u盘 下载完成后需要把镜像文件…

数据的绘画工场:Python绘图库Pyecharts,打造引人入胜的可视化效果

欢迎阅读本篇文章&#xff0c;本文将带您从零开始&#xff0c;逐步掌握使用Pyecharts库进行数据可视化的技能。Pyecharts是一个基于Echarts的Python可视化库&#xff0c;能够轻松创建各种交互式图表和地图&#xff0c;无论您是数据分析新手还是有经验的开发者&#xff0c;本文都…