python面试题——什么是GIL ;什么时候释放GIL锁;互斥锁(同步锁)和GIL的区别

一、什么是GIL

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

我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有。

二、什么时候释放GIL锁

1、某个线程运行完后其他线程才能运行。
2、如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。

三、互斥锁(同步锁)和GIL的区别

1、举例:多线程执行任务造成数据混乱的问题

import threading

g_num=0
def run():
    global g_num

    for i in range(1000000):
        g_num+=1
    print(f'当前线程{threading.current_thread().name}的执行结果:',g_num)


if __name__ == '__main__':
    thread=[]
    for i in range(10):
        t=threading.Thread(target=run)
        t.start()
        thread.append(t)

    for t in thread:
        t.join()
    print('主线程执行完毕')

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

当前线程Thread-1的执行结果: 1000000
当前线程Thread-2的执行结果:当前线程Thread-3的执行结果: 1581377
 当前线程Thread-4的执行结果:2690126
 当前线程Thread-5的执行结果: 35138763690126

当前线程Thread-6的执行结果: 当前线程Thread-7的执行结果: 5545936
4690126
当前线程Thread-8的执行结果:当前线程Thread-9的执行结果:  6244936
当前线程Thread-10的执行结果: 82094017209401

主线程执行完毕

Process finished with exit code 0

2、数据混乱的原因:

cpu分成多个时间片段,启动10线程,分配10个cpu时间片段,当我累加数字设置比较小的时候,在单个cpu时间片段内,for循环代码就执行完,就不会产生数据混乱的。当我数据设置的比较大时,在单个cpu时间片段内,for循环代码就执行不完,并且没有分配2个或2个以上的连续的cpu时间片段,导致一个cpu时间片段没有执行完该线程,下一个线程开始执行了

问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为"线程不安全”"。

3、解决数据混乱(同步锁、互斥锁)

lock=Lock():创建同步锁
lock.acquire():获得这把锁的钥匙
lock.release():释放锁;如果不释放锁,其他的线程拿不到锁,是不会运行的;
释放锁后其他线程会抢这把锁。谁先抢到这把锁不一定
必须使用同一把锁

import threading


g_num=0
def run():
    global g_num

    lock.acquire()
    for i in range(1000000):
        g_num+=1
    print(f'当前线程{threading.current_thread().name}的执行结果:',g_num)
    lock.release()

if __name__ == '__main__':
    lock=threading.Lock()
    thread=[]
    for i in range(10):
        t=threading.Thread(target=run)
        t.start()
        thread.append(t)

    for t in thread:
        t.join()
    print('主线程执行完毕')

执行结果:

当前线程Thread-1的执行结果: 1000000
当前线程Thread-2的执行结果: 2000000
当前线程Thread-3的执行结果: 3000000
当前线程Thread-4的执行结果: 4000000
当前线程Thread-5的执行结果: 5000000
当前线程Thread-6的执行结果: 6000000
当前线程Thread-7的执行结果: 7000000
当前线程Thread-8的执行结果: 8000000
当前线程Thread-9的执行结果: 9000000
当前线程Thread-10的执行结果: 10000000
主线程执行完毕

四、总结:

多线程编程时通过调用threading模块的Lock函数,来获取一把互斥锁。互斥锁就是对共享数据进行锁定,保证同一时刻只有一个线程操作数据,是数据级别的锁。

GIL锁是解释器级别的锁,保证同一时刻进程中只有一个线程拿到GIL锁,拥有执行权限。

物联沃分享整理
物联沃-IOTWORD物联网 » python面试题——什么是GIL ;什么时候释放GIL锁;互斥锁(同步锁)和GIL的区别

发表评论