当前位置:   article > 正文

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

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

主进程的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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

workwork1 1921583
2000000
主线程执行结果 2000000


在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/687154
推荐阅读
相关标签
  

闽ICP备14008679号