Python‘最难’的问题——GIL问题

一、什么是GIL

GIL(解释器全局锁)

从名字上看能告诉我们很多东西,很显然,这是一个加在解释器上的全局(从解释器的角度看)锁(从互斥或者类似角度看)。

首先来看回顾一下什么是锁:

为什么加锁

由于多线程共享进程的资源和地址空间,因此,在对这些公共资源进行操作时,为了防止这些公共资源出现异常的结果,必须考虑线程的同步和互斥问题。

加锁的作用

1、用于非线程安全,2、控制一段代码,确保其不产生调度混乱。

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中,全局解释器锁(global interpreter lock, GIL)是一个互斥体,它防止多个本机线程同时执行Python字节码。这个锁是必要的,主要是因为CPython的内存管理不是线程安全的。(然而,自从GIL存在以来,其他特性已经逐渐依赖于它强制执行的保证。)

二、GIL的影响

GIL的设计缺陷

从上文的介绍和官方的定义来看,GIL就是一把全局排他锁。这种方式当然很安全,但是这对于任何Python程序来说,不管有多少的处理器,任何时候都总是只有一个线程在执行。毫无疑问全局锁的存在会对多线程的效率有不小影响。

但是我们课上讲的例子,并不是这样啊

上课的多线程例子:

from threading import Thread

import time

def task():

time.sleep(5)

def run():

t1 = Thread(target=task)

t2 = Thread(target=task)

start = time.time()

t1.start()

t1.join()

t2.start()

t2.join()

end = time.time()

print(f'Total time: {end - start}')

'''

串行结果:

Total time:10

'''

t1.start()

t2.start()

t1.join()

t2.join()

'''

并行结果:

Total time:5

'''

但是!

看看这个

from threading import Thread

import time

def counter():

# 计数到一亿

i = 0

for _ in range(100000000):

i += 1

return True

def run():

t1 = Thread(target=counter)

t2 = Thread(target=counter)

start = time.time()

t1.start()

t1.join()

t2.start()

t2.join()

end = time.time()

print(f'Total time: {end - start}')

'''

串行结果(即单线程):

Total time: 15.838918209075928

'''

t1.start()

t2.start()

t1.join()

t2.join()

'''

并行结果:

Total time: 16.79609990119934

(其实他们两个结果我跑的时候不相上下,但是也能说明问题)

'''

if __name__ == '__main__':

run()

问题来了。

为什么多线程并行比单线程慢,但是一些例子为什么多线程并行时间又更少?

刚刚也说了是因为GIL导致的,python解释器任何时候都是一个线程在执行。

一些情况下多线程并行快的原因是: 线程做的是i/o操作, 可以挂起当前线程去执行下一线程。因为遇到像 i/o操作这种 会有时间空闲情况 造成cpu闲置的情况会释放GIL

所以在python上只要在进行耗时的IO操作的时候,能释放GIL,这样也还是可以提升运行效率的。

为什么GIL有这个缺陷而不改进?

改不了!

为什么改不了

历史遗留问题:因为硬件的升级cpu单核变多核,当时python开发者为了利用多核,就出现了多线程编程,而随之带来的就是线程间数据一致性和状态同步的困难。 python开发者的解决方法就是加GIL这把大锁。

但是人们之后发现了这种多线程编程实现方式是垃圾的,想去除他,但是这时候已经发现离不开他了,大量的开发者已经重度依赖GIL了。

有了GIL的存在,python有这两个特点

1、进程可以利用多核,但是开销大。

2、多线程开销小,却无法利用多核优势。

也就是说Python中的多线程是假的多线程,Python解释器虽然可以开启多个线程,但同一时间只有一个线程能在解释器中执行,而做到这一点正是由于GIL锁的存在,它的存在使得CPU的资源同一时间只会给一个线程使用,而由于开启线程的开销小,所以多线程才能有一片用武之地,不然就真的是鸡肋了。

而python的多线程到底有没有用呢?

​有用。我们需要看任务是I/O密集型,还是计算密集型:

如果是I/O密集型任务,有再多核也没用,即能开再多进程也没用,所以我们利用python的多线程一点问题也没有;

如果是计算密集型任务,我们就直接使用多进程就可以了

如何解决GIL锁带来的问题

1、不用cpython,使用jpython(不太推荐)

2、使用多进程完成多线程任务(python专家推荐)

用multiprocess来代替Thread

multiprocess库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。它完整的复制了一套thread所提供的接口方便迁移。唯一的不同就是它使用了多进程而不是多线程。每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。

但是它的引入会增加程序实现时线程间数据通讯和同步的困难。

3、使用多线程时用c语言实现

python gil 解决_Python GIL问题相关推荐

  1. python gil锁_python GIL锁问题

    一.GIL是什么 官方解释: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple na ...

  2. python gil原理_Python GIL深入浅出

    概述 GIL(Global Interpreter Lock)是什么东东?为什么当一些Pythoners在开发一些多线程操作的时候,都会有些很多疑问?多线程真的很糟糕吗?我该如何实现多线程并发操作?今 ...

  3. python gil锁_python GIL锁

    为什么要有GIL GIL GIL(global interpreter lock),全局解释器锁,是很多编程语言实现中都具有的特性,由于它的存在,解释器无法实现真正的并发.它也是 Python 中经常 ...

  4. python gil 解决_Python的GIL问题

    python GIL问题的解释(global interpreter lock) 早期cpython(python最主要的解释器)为了实现多线程的功能,提高CPU利用率,暴力无脑使用了GIL机制(全局 ...

  5. python gil 解除_python GIL的解读

    前言 本篇文章主要是看完UnderstandingGIL.pdf后的一些理解 http://www.dabeaz.com/python/UnderstandingGIL.pdf GIL什么是? 简单翻 ...

  6. python性能解决_Python性能优化的20条建议

    优化算法时间复杂度 算法的时间复杂度对程序的执行效率影响最大,在Python中可以通过选择合适的数据结构来优化时间复杂度,如list和set查找某一个元素的时间复杂度分别是O(n)和O(1).不同的场 ...

  7. gil 简述_python GIL简述

    标签: 首先让我们了解一下并发和并行的概念:什么是并发什么是并行,他们的区别是什么? 举个简单的例子: 你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行. 你吃饭吃 ...

  8. python全局解释锁_Python GIL 全局解释性锁介绍

    什么是GIL GIL (Global Interpreter Lock),全局解释性锁,它上锁的对象是解释器,而Python代码的运行需要解释器进行解释成字节码并提供虚拟机运行,这么大粒度的锁意味着, ...

  9. python解释器的工作原理_Python GIL全局解释器锁详解(深度剖析)

    通过前面的学习,我们了解了 Pyton 并发编程的特性以及什么是多线程编程.其实除此之外,Python 多线程还有一个很重要的知识点,就是本节要讲的 GIL. GIL,中文译为全局解释器锁.在讲解 G ...

最新文章

  1. verilog中数组的定义_systemverilog中的数组操作
  2. 刘强东:猪飞到天疯狂了十几秒 但摔下死得更快
  3. installshield 4075 错误
  4. 【已解决】Android 如何让应用在后台运行
  5. 不一样 使用别名 数据字段和bean_【修炼内功】[spring-framework] [3] Bean是如何创建又是如何销毁的?...
  6. BZOJ 1020 安全的航线flight
  7. mongodb 持久化 mysql_最详细的python爬虫指南(四):持久化操作(mongoDB、mysql)...
  8. 清除sqlserver日志方法(不适合always on)
  9. 在hisi上QT交叉编译过程(带webengine)
  10. java过去localhost出错,http://localhost:8080/ 访问出404,不知道哪错了
  11. Spring源码之bean的销毁registerDisposableBeanIfNecessary方法解读
  12. java rsa密钥转pkcs8_openssl RSA密钥格式PKCS1和PKCS8相互转换
  13. 软件测试-xx银行面试经验过程详细版
  14. citespace:Your version‘s status cannot be verified due to network issue. Check your network conne
  15. 浏览器服务器文件夹在哪里找,IE临时文件夹在哪?Win7系统下如何查找临时文件夹...
  16. Apache HBase【从无到有从有到无】【AH8】RegionServer调整大小的经验法则
  17. 微信分享到朋友圈的链接没有图片。开发工具中正常没有报错-解决方案
  18. Windows安装Redis5.x
  19. 有关七巧板复原的算法初步探讨
  20. 使用google浏览器添加并翻译英文无字幕视频

热门文章

  1. Conda executable is not found
  2. 引用 PS鼠绘青纯美少女教程
  3. Js获取当前时间戳并格式化
  4. mysql virtual 关键字_C# virtual关键字详解
  5. 11.设计模式--装饰者模式(Decorator模式)
  6. 常见的数据结构基本介绍
  7. Favicon.ico图片在线制作图标网站php源码
  8. iOS 忘记访问限制的密码后找回的方法
  9. html+style+标签,20 + HTML表单最佳实践入门
  10. java hashmap is遍历_关于内存:在Java(或Scala)中遍历HashMap的HashMap