在Python中使用多线程,如果你对GIL本身没有一定的了解;那么很有可能你只是写出了正确的多线程代码,而并没有达到多线程的目的,甚至截然相反的效果。下面介绍了Python中GIL的作用和局限性,并提供了避免GIL影响性能的几个建议。

GIL是CPython中特有的全局解释器锁(其它实现版本因为有自己线程调度机制,所以没有GIL机制)。本质上讲它就是Python进程中的一把超大锁。这把锁在解释器进程中是全局有效的,它主要锁定Python线程的CPU执行资源。

换句话说,在CPython解释器中当一个线程需要执行CPU进行计算之前,它需要先获得这把大锁;否则即使已经被操作系统调度出来,但仍然无法执行计算。所以CPython解释器中,线程的想要执行CPU指令需要2个条件:

  1. 被操作系统调度出来【操作系统允许它占用CPU】
  2. 获取到GIL【CPython解释器允许它执行指令】

非常不幸的是,我们并不总是能满足这2个条件。经常出现的情况是:已经满足条件1,却被条件2限制。而这就是GIL影响Python性能的主要原因【其它语言只需满足条件1即可】。

如果Python(这里默认指CPython)在单核CPU的机器上执行,它的多线程与单线程、以及其它语言的多线程在本质上并没有什么不一样。【所有线程都是轮流占用CPU执行指令】

而如果Python在多核CPU机器上执行的时候,性能则会非常槽糕。主要原因是在单核的时候,同时只有一个线程在执行CPU,所以这个线程总是能获取到GIL。而换到多核的时候,同时会有多个线程在不同的CPU核心上执行,此时不同线程之间就需要竞争GIL,而GIL只能同时被一个线程申请到,所以会导致其它线程处于闲置状态【即使它已经拥有了CPU资源】。所以Python在多核CPU上的多线程始终只有单线程在跑程序。

在早期的Python版本(3.2之前)中,GIL除了会让多线程在多核机器下表现槽糕外,它还会导致某些线程场景占用GIL,而其它线程却无法申请到。典型场景是:

  • 在2个线程的情况下
  • 一个是IO密集型线程
  • 一个是计算密集型线程

那么最后的结果便是,一旦计算密集型线程获得了GIL,那么它在很长一段时间内都将占据GIL,甚至一直到该线程执行结束。因为计算密集型线程在释放GIL之后又会立即去申请GIL,并且通常在其它线程还没有调度完之前它就已经重新获取到了GIL。【因为GIL它没有锁通知机制,比如:Condition锁】

在Python3.4之后,由于对GIL有了较大的改进。在单核的情况下,对于单个线程长期占用GIL的情况有所好转;但是在多核的情况下,性能仍然还是没有多大的改善。

很多时候有些事情我们无法改变,但是生活给了我们智慧;所以为了客服困难,我们始终还是能找到解决办法的。虽然默认情况下GIL对Python多线程的多核的情况下有较大的性能影响,但是为了能在Python中利用多核来提高计算效率,还是有如下的方法可以实现的:

  • 使用python3.4或更高版本(对GIL机制进行了优化)
  • 使用多进程替换多线程(多进程之间没有GIL,但是进程本身的资源消耗较多)
  • 使用C编写高性能模块(with nogil调出GIL限制)
  • 指定cpu运行线程(使用affinity模块)
  • 使用Jython、IronPython等无GIL解释器
  • 全IO密集型任务时使用多线程
  • 使用协程(高效的单线程模式,也称微线程;通常与多进程配合使用)

关于GIL的实现原理、改进内容、适用场景等知识点,可以查看这里。更多关于学习Python的文章请关注下方二维码。

再谈Python多线程--避免GIL对性能的影响相关推荐

  1. 再谈Python的引用和变量

    再谈Python的引用和变量 上一次我们介绍了一个有用的代码可视化工具Python Tutor,说到我们还要通过这个工具再探讨一下Python引用相关的话题.因此有了本文. 引用 观察代码框下方的布局 ...

  2. Python GIL 系列之再谈Python的GIL

    1. 之前写过一篇<通过实例认识Python的GIL>的文章,感觉有些意犹未尽 2. 这次对例子作了些扩展,进一步的分析GIL对Python程序的影响 2.1 先来看例子: [python ...

  3. python多线程与GIL

    目录 1.GIL 1.1 为什么要有GIL 1.2 GIL的运作方式 1.3 GIL带来的问题 2.多线线程 2.1 线程的调度和启动 3.线程构造与使用 3.1调用Thread类构造器创建线程 3. ...

  4. 浅谈python中的GIL

    GIL是什么 首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念.就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可 ...

  5. 浅谈Python多线程

    线程 一.什么是线程? 操作系统原理相关的书,基本都会提到一句很经典的话: "进程是资源分配的最小单位,线程则是CPU调度的最小单位". 线程是操作系统能够进行运算调度的最小单位. ...

  6. python_浅谈python多线程

    一.什么是线程和进程 这个查了很多资料,最后我理解是这样的 进程:是 CPU 资源分配的最小单位,它主要用来就是资源的分配 线程:是 CPU 调度执行的最小单位,它主要用来系统调度 通俗的说我们电脑任 ...

  7. 再谈Python启动器与Anaconda解释器的关联问题

    问题 是否可以通过Python启动器(py.exe)启动Anaconda安装的Python解释器? 分析 一. 启动Python解释器有三种方法: 根据指定Python解释器的路径执行.按照这种方法是 ...

  8. c语言多线程转python多线程,真正的python 多线程!一个修饰符让你的多线程和C语言一样快...

    > Python 多线程因为GIL的存在,导致其速度比单线程还要慢.但是近期我发现了一个相当好用的库,这个库只需要增加一个修饰符就可以使原生的python多线程实现真正意义上的并发.本文将和大家 ...

  9. python多线程加锁异步处理装饰器

    2019独角兽企业重金招聘Python工程师标准>>> 前言: 虽谈python多线程带有全局锁PIL,似乎对性能提升没什么意义,一般考虑多进程或者协程,但PIL没有被去掉还是应该有 ...

最新文章

  1. Java中对象引用的机制,及特点
  2. document 获得元素节点,属性节点,文本节点
  3. Algorithm:【Algorithm算法进阶之路】之数据结构基础知识
  4. php rss xml,php – 如何使用simplexml解析RSS中的标记
  5. quartz-misfire 错失、补偿执行
  6. 改变Android的hello world程序字体颜色和背景颜色
  7. 20 个使用 Java CompletableFuture的例子
  8. Silverlight WCF RIA服务(十三)数据 3
  9. 重构手册阅读笔记:重构的含义
  10. jq 实现头像(气泡式浮动)
  11. 关于公布部分非法刊物的通知及冀职改办字[2006]48号
  12. 《SpringSecurity in Action》四:Session共享下的Session并发控制问题
  13. Photoshop入门教程:画笔工具轻松打造轻纱效果
  14. java计算机毕业设计物流公司停车位管理源程序+mysql+系统+lw文档+远程调试
  15. English trip 自习内容 句子结构和成分
  16. TensorFlow练手项目二:基于循环神经网络(RNN)的古诗生成器
  17. win10 redis集群搭建 ruby
  18. 用canvas 绘制一个灰太狼
  19. 基于java的校园网站管理系统
  20. Android apm监控框架,移动性能监控 SDK 详细集成文档

热门文章

  1. Code-Switch文本的合成方案列举
  2. java怎么加工具栏_Java入门-考无忧教你添加工具栏
  3. 企业微信公众号的运营策略有哪些?
  4. 小宝宝取名:诗经楚辞灵动好听的女孩名字
  5. 今天发现了WinHex的一个有趣汉化方法
  6. 从qq for android登录,QQ for Android v8.0.0 企业版系统发布下载
  7. 苹果笔不用原装可以吗?Apple Pencil平替笔推荐
  8. 计算机乐谱制作师专业,计算机乐谱制作师: 基础知识
  9. windows7系统无法连接服务器,Win7系统玩LOL提示无法连接服务器的解决办法
  10. 好心情:那个总爱逗我笑的朋友,得了抑郁症