既然有GIL了那么为什么在python中多线程编码时候还需要加锁?

GIL

由于 python 解释器(Cpython interpreter)不是线程安全(thread-safe)的,所以 Cpython interpreter 的实现中使用了GIL(global interpreter lock)来阻止多线程同时在一个 pyobject 上操作。这里所说的 “不是线程安全“ 是指Cpython interpreter在内存管理上不是线程安全的。比如,两个线程同时增加一个 python object 的引用计数(内存管理用到),如果没有GIL,那么这个 python object 的 reference count 只会增加一次。因此,需要有这么一个规则:只有获得GIL的线程才能在 python object 上操作或者调用 python/c API 函数。
但是这么以来,貌似在interpreter执行的python程序只能单线程串行执行了么?不是,interpreter 为了模拟并发执行(concurrency of execution),会去尝试切换线程(详情可参考sys.setswitchinterval()), 锁也会在当前线程block时候(例如读写文件等阻塞io情况下)释放掉,以便让给其他线程。interpreter 也会在执行够一定数量(通常是100)的 opcode 后释放锁。

例子

import threading
import time

total = 0
lock = threading.Lock()

def increment_n_times(n):
    global total
    for i in range(n):
        total += 1

def safe_increment_n_times(n):
    global total
    for i in range(n):
        lock.acquire()
        total += 1
        lock.release()

def increment_in_x_threads(x, func, n):
    threads = [threading.Thread(target=func, args=(n,)) for i in range(x)]
    global total
    total = 0
    begin = time.time()
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()
    print('finished in {}s.\ntotal: {}\nexpected: {}\ndifference: {} ({} %)'
           .format(time.time()-begin, total, n*x, n*x-total, 100-total/n/x*100))

reference

https://wiki.python.org/moin/GlobalInterpreterLock
https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock
https://stackoverflow.com/questions/40072873/why-do-we-need-locks-for-threads-if-we-have-gil

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值