python的GIL

朋友们,我是床长! 如需转载请标明出处:http://blog.csdn.net/jiangjunshow

 

GIL为何物

GIL(Global Interpreter Lock),也称为全局解释器,看下官方解释

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.)

主要意思为:

GIL是一个互斥锁,它防止多个线程同时执行Python字节码。这个锁是必要的,主要是因为CPython的内存管理不是线程安全的

>Python与GIL

Python的GIL只是CPython(Python解释器)的一个问题,那么Python又有哪些解释器,它们也存在和CPython同样的问题吗?那么什么又是解释器呢?

什么是解释器

我们写的代码计算机是如何识别的呢,计算机也拥有和人类相同的思维和语言吗?显然不是的;计算机只能识别机器指令语言也就是0和1,那么我们编写的程序计算机是如何识别的呢?这就是解释器的作用了,解释器将我们编写的Python代码翻译为机器指令语言,Python解释器本身也是个程序,它是解释Python代码的,叫做解释器.

Python解释器有哪些

  1. CPython: 官方默认版本,使用C语言开发,是Python使用最广泛的解释器,有GIL.
  2. IPython: IPython是基于CPython之上的交互式解释器,其它方面和CPython相同.
  3. PyPy: PyPy采用JIT(Just In Time)也就是即时编译编译器,对Python代码执行动态编译,目的是加快执行速度,有GIL.
  4. Jython: 运行在Java平台上的解释器,把Python代码编译为Java字节码执行,没有GIL.
  5. IronPython: IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码,没有GIL.

>GIL解决了Python什么问题呢

Python内部对变量或数据对象使用了引用计数器,我们通过计算引用个数,当个数为0时,变量或者数据对象就被自动释放

In [1]: import  sys                                                  

In [2]: count_var = "test1"                                         

In [3]: sys.getrefcount(count_var)                                  
Out[3]: 2

In [4]: add_var = count_var                                         

In [5]: sys.getrefcount(add_var)                                    
Out[5]: 3
复制代码

这个引用计数器需要保护,当多个线程同时修改这个值时,可能会导致内存泄漏;SO,我们使用锁来解决这个问题,可有时会添加多个锁来解决,这就会导致另个问题,死锁;

为了避免内存泄漏和死锁问题,CPython使用了单锁,即全局解释器锁(GIL),即执行Python字节码都需要获取GIL,这可以防止死锁,但它有效地使任何受CPU限制的Python程序都是单线程.

>GIL对多线程Python程序的影响

程序的性能受到计算密集型(CPU)的程序限制和I/O密集型的程序限制影响,那什么是计算密集型和I/O密集型程序呢?

计算密集型(CPU)

高度使用CPU的程序,例如: 进行数学计算,矩阵运算,搜索,图像处理等.

I/O密集型

I/0(Input/Output)程序是进行数据传输,例如: 文件操作,数据库,网络数据等


测试下顺序执行单线程和并发执行多线程的效率

- 顺序执行单线程(single_thread.py)

import threading
import time

def test_counter():
    i = 0
    for _ in range(100000000):
        i += 1
    return True

def main():
    start_time = time.time()
    for tid in range(2):
        t1 = threading.Thread(target=test_counter)
        t1.start()
        t1.join()
    end_time = time.time()
    print("Total time:{}".format(end_time-start_time))


if __name__ == "__main__":
    main()
复制代码

执行结果:

Total time: 11.299654722213745
复制代码

- 并发执行两个线程(multi_thread.py)

import threading
import time

def test_counter():
    i = 0
    for _ in range(100000000):
        i += 1
    return True

def main():
    thread_array = {}
    start_time = time.time()
    for tid in range(2):
        t = threading.Thread(target=test_counter)
        t.start()
        thread_array[tid] = t
    for i in range(2):
        thread_array[i].join()
    end_time = time.time()
    print("Total time:{}".format(end_time-start_time))


if __name__ == "__main__":
    main()
复制代码

执行结果:

Total time:13.7098388671875
复制代码

GIL对I/O绑定多线程程序的性能影响不大,因为线程在等待I/O时共享锁.

GIL对计算型绑定多线程程序有影响,例如: 使用线程处理部分图像的程序,不仅会因锁定而成为单线程,而且还会看到执行时间的增加,这种增加是由锁的获取和释放开销的结果.

>可以去掉累赘GIL吗

有大佬试过,只能说结果不尽人意0 .0,等待着吧

>SO,如何处理Python中的GIL

  • 计算密集型程序
    • 使用多进程(什么是多进程呢,后续道来)
    • 使用其它语言(将计算密集程序放到其它语言中执行)
    • 替换解释器(可以自己尝试)
    • 等大神解决GIL0 .0
  • I/O密集型程序
    • 使用多线程
    • 使用多进程
    • 使用多进程+多线程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值