GIL全局解释器锁

Posted mcc61

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GIL全局解释器锁相关的知识,希望对你有一定的参考价值。

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple 
native threads from executing Python bytecodes at once. This lock is necessary mainly 
because CPython’s memory management is not thread-safe. (However, since the GIL 
exists, other features have grown to depend on the guarantees that it enforces.

在Cpython中,GIL这个全局解释器锁就是一个互斥锁,一次只能让一个线程运行。这把锁是必须且重要的是因为Cpython解释器的内存管理对线程来说并不是一个安全的。

然而,自从GIL存在,其他特性已经成长为依赖于它强制执行的保证。(就是所有的线程都要去抢这把锁)

 

假设没有GIL这把锁的情况下,会出现的情况!!!

* 为什么要有GIL是因为它内部的垃圾回收机制不是线程安全的
* 垃圾回收机制也是一个任务,跟你的代码不是串行运行,如果是串行会明显有卡顿
* 这个垃圾回收到底是开进程还是开线程?肯定是线程,线程肯定也是一段代码,所以想运行也必须要拿到python解释器
* 假设能够并行,会出现什么情况?一个线程刚好要造一个a=1的绑定关系之前,这个垃圾线程来扫描,矛盾点就来了,谁成功都不

 

1.python中的多线程到底有没有用?

单核情况下:四个任务

多核情况下:四个任务

计算密集型:一个任务算十秒,四个进程和四个线程,肯定是进程快

IO密集型:任务都是纯io情况下,线程开销比进程小,肯定是线程好

 

import os,time
from multiprocessing import Process
from threading import Thread

‘‘‘
def work():
    res=0
    for i in range(100000000):#做的是计算型的操作
        res*=i

if __name__ == ‘__main__‘:
    l=[]
    print(os.cpu_count())  #8
    start=time.time()
    for i in range(8):#产生8个进程同时执行
        p=Thread(target=work)#run time is 39.95239758491516
        # p=Process(target=work)  #run time is 8.076356410980225
        l.append(p)
        p.start()
    for p in  l:
        p.join()
    stop=time.time()
    print(‘run time is %s‘%(stop-start))
‘‘‘
#io密集型
def work():
    time.sleep(2)

if __name__ == __main__:
    start=time.time()
    l=[]
    for i in range(600): #开启600个线程
        p=Process(target=work) #run time is 11.53145694732666
        # p=Thread(target=work)  #run time is 2.06762957572937
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print(run time is %s%(stop-start))

GIL全局锁和普通锁的区别

# from threading import Thread,Lock
# import time
#
# mutex=Lock()
#
#
# n=100
#
# def task():
#
#     global n
#     mutex.acquire()
#     temp=n
#     time.sleep(0.1)
#     n=temp-1
#     mutex.release()
#
# t_list=[]
# for i in range(100):
#     t=Thread(target=task)
#     t.start()
#     t_list.append(t)
#
# for t in t_list:
#     t.join()
#
# print(n)
#     # pass
‘‘‘
对于不同的数据,要想保证安全,必须加不同的锁处理

GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程

保证的是同一个进程下多个线程之间的安全

‘‘‘
from threading import Thread,Lock

import time

mutex=Lock()
n=100

def task():
    global n
    mutex.acquire()
    temp=n
    time.sleep(0.1)  #模拟网络延迟

    n=temp-1
    mutex.release()

l_list=[]
for i in range(100):
    t=Thread(target=task)
    t.start()
    l_list.append(t)

for t in l_list:
    t.join()

print(n)  #0

死锁和递归锁

#死锁
‘‘‘
import time
from threading import Thread,Lock

mutexA=Lock()
mutexB=Lock()

class MyThead(Thread):
    def run(self):
        self.func1()
        self.func2()


    def func1(self):
        mutexA.acquire()
        print(‘%s 抢到了A锁‘ % self.name)
        mutexB.acquire()
        print(‘%s 抢到了B锁‘ % self.name)
        mutexB.release()
        print(‘%s 释放了B锁‘ % self.name)
        mutexA.release()
        print(‘%s 释放了A锁‘ % self.name)
    def func2(self):
        mutexB.acquire()
        print(‘%s 抢到了B锁‘ % self.name)
        time.sleep(1)
        mutexA.acquire()
        print(‘%s 抢到了A锁‘ % self.name)
        mutexA.release()
        print(‘%s 释放了A锁‘ % self.name)
        mutexB.release()
        print(‘%s 释放了B锁‘ % self.name)


if __name__ == ‘__main__‘:
    for i in range(10):
        t=MyThead()
        t.start()

‘‘‘
#递归锁(解决产生死锁现象)  引用计数0  同一个人(每引用一次,计数+1),下面的人必须等到第一个人释放锁才可以抢
# from threading import Thread,RLock

# mutesA=mutexB=RLock()  #抢锁之后会有一个计数,抢一次计数加1
import time
from threading import Thread,RLock

mutexA=mutexB=RLock()


class MyThead(Thread):
    def run(self):
        self.func1()
        self.func2()


    def func1(self):
        mutexA.acquire()
        print(%s 抢到了A锁 % self.name)
        mutexB.acquire()
        print(%s 抢到了B锁 % self.name)
        mutexB.release()
        print(%s 释放了B锁 % self.name)
        mutexA.release()
        print(%s 释放了A锁 % self.name)
    def func2(self):
        mutexB.acquire()
        print(%s 抢到了B锁 % self.name)
        time.sleep(1)
        mutexA.acquire()
        print(%s 抢到了A锁 % self.name)
        mutexA.release()
        print(%s 释放了A锁 % self.name)
        mutexB.release()
        print(%s 释放了B锁 % self.name)


if __name__ == __main__:
    for i in range(10):
        t=MyThead()
        t.start()


‘‘‘
自定义锁:一次acquire对应一次release,
递归锁:一次acquire可以不一定要对应release,每产生一次acquire,第一个抢到锁的人的引用计数就+1,除非第一个人释放,否则别人就不会抢到锁
递归锁是解决自定义锁出现的死锁现象
‘‘‘

信号量

#钥匙串  公共厕所

from threading import Thread,Semaphore
import time,random

sm=Semaphore(5)   #五个厕所五把锁

def task(name):
    sm.acquire()
    print(%s 正在蹲坑%name)

    #模拟蹲坑耗时
    time.sleep(random.randint(1,5))
    sm.release()

if __name__ == __main__:
    for i in range(20):
        t=Thread(target=task,args=(伞兵%s 号%i,))
        t.start()

event事件

from threading import Event,Thread

import time

event=Event()


def light():
    print(红灯亮着!)
    time.sleep(3)
    event.set()  #解除阻塞,给我的event发了一个信号
    print(绿灯亮着)


def car(i):
    print(%s 正在等红灯了%i)
    event.wait()  #阻塞
    print(%s 加油飙车%i)

t1=Thread(target=light)
t1.start()

for i in range(10):
    t=Thread(target=car,args=(i,))
    t.start()

线程queue

import queue

#普通q
# q=queue.Queue(3)
# q.put(1)
# q.put(2)
# q.put(3)
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())


#先进后出q
# q=queue.LifoQueue(5)
# q.put(1)
# q.put(2)
# q.put(3)
# q.put(4)
# print(q.get())

#优先级q
q=queue.PriorityQueue()
q.put((10,a))
q.put((1,b))
q.put((1,c))
q.put((1,a))
q.put((4,a))
print(q.get())

 

以上是关于GIL全局解释器锁的主要内容,如果未能解决你的问题,请参考以下文章

并发编程——GIL全局解释器锁死锁现象与递归锁信号量Event事件线程queue

GIL(全局解释器锁)

GIL全局解释器锁

python全局解释器锁(GIL)

GIL(全局解释器锁)

Python入门学习-DAY36-GIL全局解释器锁死锁现象与递归锁信号量Event事件线程queue