Python核心丨GIL(全局解释器锁)

GIL


每一个Python线程,在CPython解释器中执行时,都会先锁住自己的线程,阻止别的线程执行。

为什么又GIL

CPython引进GIL主要两个原因

  • 设计者为了规避类似于内存管理这样的复杂的竞争风险问题(race condition)

  • 二是因为CPython大量使用C语言库,但大部分C语言库都不是原生线程安全的(线程安全会降低性能和增加复杂度)

GIL是如何工作的

如下图,其中Thread 1、2、3轮流执行,每一个线程在开始执行时,都会锁住GIL,以阻止别的线程执行;同样的,每一个线程执行完一段后,会释放GIL,以允许别的线程开始利用资源

在这里插入图片描述
CPython还有另一个机制,叫做check_interval,意思是CPython解释器会去轮询检查线程GIL的锁住情况。

每隔一段时间,Python解释器就会强制当前线程去释放GIL,这样别的线程才能有执行的机会。

Python的线程安全

有了GIL,也并不意味Python线程就是安全的了。


import threading

n = 0

def foo():
    global n
    n += 1

threads = []
for i in range(100):
    t = threading.Thread(target=foo)
    threads.append(t)

for t in threads:
    t.start()

for t in threads:
    t.join()

print(n)

执行的时候,大部分时候能够打印100,但也会打印99或这98.

这是因为,n +=1 这一句代码让线程并不安全。翻译foo这个函数的bytecode,可以发现,它实际由下面四行bytecode组成:

>>> import dis
>>> dis.dis(foo)
LOAD_GLOBAL              0 (n)
LOAD_CONST               1 (1)
INPLACE_ADD
STORE_GLOBAL             0 (n)

这四行bytecode中间都是有可能被打断的

注:GIL的设计,主要是为了方便CPython解释器层面的编写者,而不是Python应用层面的程序员。

作为Python的使用者,需要lock等工具,确保线程安全。

n = 0
lock = threading.Lock()

def foo():
    global n
    with lock:
        n += 1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值