当前位置: 首页 > news >正文

python——全局解释器锁(GIL)

在这里插入图片描述


进程定义:

顾名思义,就是正在运行中的程序。是操作系统中分配任务的最小基本单元;

线程定义:

线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己不拥有系统资源;但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

进程和线程的区别

1、进程是操作系统分配任务的基本单位,进程是python中正在运行的程序;当我们打开了1个浏览器时就是开始了一个浏览器进程;
线程是进程中执行任务的基本单元(执行指令集),一个进程中至少有一个线程、当只有一个线程时,称为主线程
2、线程的创建和销毁耗费资源少,进程的创建和销毁耗费资源多;线程很容易创建,进程不容易创建
3、线程的切换速度快,进程慢
4、一个进程中有多个线程时:线程之间可以进行通信;一个进程中有多个子进程时,进程与进程之间不可以相互通信,如果需要通信时,就必须通过一个中间代理实现,Queue、Pipe。
5、多进程可以利用多核cpu,多线程不可以利用多核cpu
6、一个新的线程很容易被创建,一个新的进程创建需要对父进程进行一次克隆
7、多进程的主要目的是充分使用CPU的多核机制,多线程的主要目的是充分利用某一个单核

在这里插入图片描述

多进程中,异步执行任务时,CPU内存空间不一致,但是资源数据是主进程中拷贝的;即一个新的进程创建需要对父进程进行一次克隆

进程池

进程池:可以提供指定数量的进程给用户使用,即当有新的请求提交到进程池中时,如果池未满,则会创建一个新的进程用来执行该请求;反之,如果池中的进程数已经达到规定最大值,那么该请求就会等待,只要池中有进程空闲下来,该请求就能得到执行。

作用:

1、当进程数过多时,用于限制同时执行的进程数
2、自动的释放资源,节省内存空间
3、提高效率,节省开辟进程和开辟内存空间的时间及销毁进程的时间

import os
import time
from multiprocessing import Process,Pool

number=100
def func(name):
    print(f'子进程的id:{os.getpid()},子进程的名称{name}')
    for i in range(3):
        global number
        number+=1
        print(number)
    time.sleep(1)

if __name__ == '__main__':
    print(f'主进程的id:{os.getpid()}')
    p_collects=Pool(5)
    p_collects.apply_async(func,args=('process-1',))
    p_collects.apply_async(func,args=('process-2',))

    p_collects.close()      #todo 把当前的进程池关掉,不允许去创建新的进程了
    p_collects.join()
    print('主线执行完毕')
    print(number)

主进程的id:25124
子进程的id:19928,子进程的名称process-1
101
102
103
子进程的id:27500,子进程的名称process-2
101
102
103
主线执行完毕
100

CPU密集型(计算密集型)和IO密集型

CPU密集型(计算密集型):计算圆周率、浮点运算、对视频进行高清解码
IO密集型:涉及到网络、磁盘IO的任务都是IO密集型任务,Web应用
多进程的主要目的是充分使用CPU的多核机制
多线程的主要目的是充分利用某一个单核

全局解释器锁(GIL)

GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。

保证同一个时刻只有一个线程在运行,所以python多线程并不是并行的,是并发的
对于IO密集型全局解析器锁的存在并不会提高执行的速度
即使存在GIL 在有IO等待操作的程序中,还是多线程快,当然没有资源等待的还是单线程快(科学计算,累加)

有了全局解释器锁(GIL)为什么还需要同步锁?

全局解析器锁(GIL)加在了全局了,没有加到我所想要的位置,加到什么位置不是我们决定的;
包括修改资源的程序和非修改资源的程序,如果出现在修改资源的相关代码上,肯定会出现脏数据。
同步锁:来获取一把互斥锁。互斥锁就是对共享数据进行锁定,保证同一时刻只有一个线程操作数据,是数据级别的锁。
GIL锁是解释器级别的锁,保证同一时刻进程中只有一个线程拿到GIL锁,拥有执行权限。

2个线程执行任务造成数据混乱

import threading
num=0
def work():
    global num
    for i in range(1000000):
        num+=1
    print('work',num)


def work1():
    global num
    for i in range(1000000):
        num+=1
    print('work1',num)

if __name__ == '__main__':
    t1=threading.Thread(target=work)
    t2=threading.Thread(target=work1)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('主线程执行结果',num)

执行结果:明显数据混乱了

work work1 16347351376208

主线程执行结果 1634735

说明:

代码中:num+=1,可以拆解为
num=100
100+1
num=101
同步锁这3行代码执行完毕了才会释放锁

加同步锁(with方法)

from threading import Lock

import threading
num=0
def work():
    global num
    for i in range(1000000):
        with lock:
            num+=1
    print('work',num)


def work1():
    global num
    for i in range(1000000):
        with lock:
            num+=1
    print('work1',num)

if __name__ == '__main__':
    lock=Lock()
    t1=threading.Thread(target=work)
    t2=threading.Thread(target=work1)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('主线程执行结果',num)

work 1845334work1 2000000

主线程执行结果 2000000

加同步锁(acquire方法和release方法)

from threading import Lock

import threading
num=0
def work():
    global num
    for i in range(1000000):
        lock.acquire()
        num+=1
        lock.release()
    print('work',num)


def work1():
    global num
    for i in range(1000000):
        lock.acquire()
        num += 1
        lock.release()
    print('work1',num)

if __name__ == '__main__':
    lock=Lock()
    t1=threading.Thread(target=work)
    t2=threading.Thread(target=work1)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('主线程执行结果',num)

workwork1 1921583
2000000
主线程执行结果 2000000


在这里插入图片描述

相关文章:

  • 【01-机器学习入门:理解Scikit-learn与Python的关系】
  • 线性代数 --- 计算斐波那契数列第n项的快速算法(矩阵的n次幂)
  • 机器学习模型保存和导出pmml文件(python代码)
  • Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之六 简单进行人脸训练与识别
  • TypeError: Unknown file extension “.ts“
  • Chrome 侧边栏开发示例
  • vmware安装centos 7.9 操作系统
  • Angular 中的响应式表单:监听变化
  • 【kubernetes】关于k8s集群的资源发布方式(灰度/滚动发布)
  • 【并发编程】深入理解ReentrantLock使用方法与原理解析(1)
  • 新能源汽车交流充电桩开发介绍
  • 肖恩排序。
  • 武汉市服务业领军企业认定条件、流程及申报政策奖励补贴标准
  • 我的第一篇技术博客 —— 梦的开始
  • 变分自编码器VAE的直观理解与原理推导 及 问题记录
  • 【python】准点跑路人必备小程序~ 不信你用不到
  • 10个常见的使用场景,助你从 Vue2 丝滑过渡到 Vue3 !
  • Java线程安全的时间类
  • 驱动开发:内核枚举IoTimer定时器
  • sumo的简单使用
  • 【C++】C++入门
  • Docker精通:微服务
  • HCIA-LTE学习总结03~04
  • Python Apex Legends 武器自动识别与压枪 全过程记录
  • 『Android』Toolbar+DrawerLayout+NavigationView实现类似QQ侧边栏效果
  • 10.13面试整理
  • 下一代 IDE 工具 JetBrains Fleet 正式公测
  • Node.js3---nodejs的内置模块之url模块
  • 什么样的小程序才能留住客户?
  • EXCEL表格-系统时间及进度自动记录工具制作
  • 走进元宇宙--手势交互技术详解
  • Zookeeper集群安装部署