一 介绍

'''
定义:
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解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL

二 GIL介绍

GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。

可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。

要想了解GIL,首先确定一点:每次执行python程序,都会产生一个独立的进程。例如python test.py,python aaa.py,python bbb.py会产生3个不同的python进程

'''
#验证python test.py只会产生一个进程
#test.py内容
import os,time
print(os.getpid())
time.sleep(1000)
'''
python3 test.py
#在windows下
tasklist |findstr python
#在linux下
ps aux |grep python

在一个python的进程内,不仅有test.py的主线程或者由该主线程开启的其他线程,还有解释器开启的垃圾回收等解释器级别的线程,总之,所有线程都运行在这一个进程内,毫无疑问

#1 所有数据都是共享的,这其中,代码作为一种数据也是被所有线程共享的(test.py的所有代码以及Cpython解释器的所有代码)

#2 所有线程的任务,都需要将任务的代码当做参数传给解释器(的代码)去执行,即所有的线程要想运行自己的任务,首先需要解决的是能够访问到解释器(的代码)。

综上:

如果多个线程的target=work,那么执行流程是

多个线程先访问到解释器的代码,即拿到执行权限,然后将target的代码交给解释器的代码去执行

解释器的代码是所有线程共享的,所以垃圾回收线程也可能访问到解释器的代码而去执行,这就导致了一个问题:对于同一个数据100,可能线程1执行x=100的同时,而垃圾回收执行的是回收100的操作,解决这种问题没有什么高明的方法,就是加锁处理,如下图的GIL,保证python解释器同一时间只能执行一个任务的代码

三 GIL与多线程

有了GIL的存在,同一时刻同一进程中只有一个线程被执行

听到这里,有的同学立马质问:进程可以利用多核,但是开销大,而python的多线程开销小,但却无法利用多核优势,也就是说python没用了,php才是最牛逼的语言

别着急啊,老娘还没讲完呢。

要解决这个问题,我们需要在几个点上达成一致:

#1. cpu到底是用来做计算的,还是用来做I/O的?
#2. 多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能
#3. 每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处 

结论:

  对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用

当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),这是因为一个程序基本上不会是纯计算或者纯I/O,所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型,从而进一步分析python的多线程到底有无用武之地

#结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

四 多线程性能测试

计算密集型:多进程效率高

from multiprocessing import Process
from threading import Thread
import os,time
def work():
    res=0
    for i in range(100000000):
        res*=i

if __name__ == '__main__':
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(4):
        p=Process(target=work) #耗时5s多
        p=Thread(target=work) #耗时18s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))

I/O密集型:多线程效率高

from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
    time.sleep(2)
    print('===>')

if __name__ == '__main__':
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(400):
        # p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
        p=Thread(target=work) #耗时2s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))

应用:

多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析

GIL全局解释锁的更多相关文章

  1. GIL全局解释锁,死锁,信号量,event事件,线程queue,TCP服务端实现并发

    一.GIL全局解释锁 在Cpython解释器才有GIL的概念,不是python的特点 在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势. 1.GIL介绍 ...

  2. 20191031:GIL全局解释锁

    20191031:GIL全局解释锁 总结关于GIL全局解释锁的个人理解 GIl全局解释锁,本身不是Python语言的特性,而是Python语言底层的c Python解释器的一个特性.在其他解释器中是没 ...

  3. ~~并发编程(十一):GIL全局解释锁~~

    进击のpython ***** 并发编程--GIL全局解释锁 这小节就是有些"大神"批判python语言不完美之处的开始 这一节我们要了解一下Cpython的GIL解释器锁的工作机 ...

  4. python中的GIL(全局解释锁)多线程能够提升效率

    预启动的时候,应用程序仍然会调用 OnLaunched 方法的,在 OnLaunched 方法调用之后,会马上发生 Suspending 事件,随后应用就会暂停. 我先基于develop主分支拉出一个 ...

  5. 并发、并行、同步、异步、全局解释锁GIL、同步锁Lock、死锁、递归锁、同步对象/条件、信号量、队列、生产者消费者、多进程模块、进程的调用、Process类、

    并发:是指系统具有处理多个任务/动作的能力. 并行:是指系统具有同时处理多个任务/动作的能力. 并行是并发的子集. 同步:当进程执行到一个IO(等待外部数据)的时候. 异步:当进程执行到一个IO不等到 ...

  6. GIL全局解释器锁、死锁、递归锁、线程队列

    目录 GIL全局解释锁 多线程的作用 测试计算密集型 IO密集型 死锁现象 递归锁 信号量(了解) 线程队列 GIL全局解释锁 GIL本质上是一个互斥锁. GIL是为了阻止同一个进程内多个进程同时执行 ...

  7. 什么是python的全局解释锁(GIL)

    GIL解决了Python中的什么问题? 为什么选取GIL作为解决方案? 对多线程Python程序的影响 为什么GIL还没有被删除? 为什么在Python 3 中GIL没有被移除? 如何处理Python ...

  8. 全局解释锁GIL

    ''' 定义: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native th ...

  9. Python自动化 【第九篇】:Python基础-线程、进程及python GIL全局解释器锁

    本节内容: 进程与线程区别 线程 a)  语法 b)  join c)  线程锁之Lock\Rlock\信号量 d)  将线程变为守护进程 e)  Event事件 f)   queue队列 g)  生 ...

随机推荐

  1. 实用 PXE 配置:不断更新中...

    default menu.c32 #--------------------------------todo----------------------# 不过,实用http,nfs.cdrom等方式 ...

  2. ECS上搭建Docker(CentOS7)

    ECS上搭建Docker(CentOS7) centos下 yum快速安装maven ## 安装jdk8 yum install -y java-1.8.0-openjdk* ## 安装maven w ...

  3. VS.NET(C#)--2.4_aspx默认页面模板代码

    默认模板代码 客户端浏览器将忽视<script>块间任何字符,不在页面输出.通过<%=DataTime.Now.ToString() %>      将服务端代码放中间 < ...

  4. Flask模板渲染

    目录 Flask模板渲染 Jinja2模板引擎简介 模板 Jinja2 模板变量 变量 控制结构 宏,类似Python代码中的函数 模板继承 包含(Include) 过滤器 链式调用 常见内建过滤器 ...

  5. Vue递归组件实现层层嵌套显示数据

    问题来自朋友...记录一下 需求是表格头部后端返回的数据中是不确定的 n维数据,表头存在于 listVo 字段中,如何实现层层显示呢? 温馨提示,以下内容为5张大图,请打开 WIFI 享用... 以下 ...

  6. APS中生产计划排程模块的基本原理

    高级计划系统(APS)作为ERP和MES的补充,用于协调物流.开发瓶颈资源和保证交货日期. APS包括需求和供应计划.运输和生产计划排程等各种供应链计划模块,本文主要介绍APS中生产计划排程模块的基本 ...

  7. cpio建立、还原备份档

    1. 简介 加入.解开cpio或tar备份档内的文件 与tar相似,将文件归档到硬盘或磁带等存储设备中 2. tar比较 在所处理的文件类型方面,它比tar更全面,但也更复杂 cpio比tar更为可靠 ...

  8. JavaScript 弹出框

    JavaScript 有三种类型的弹出框:警告框.确认框和提示框. 警告框 如果要确保信息传递给用户,通常会使用警告框. 当警告框弹出时,用户将需要单击“确定”来继续. 语法 window.alert ...

  9. 集合(set)

    '''set是一个无序(不支持索引和切片)而且不重复的集合,有些类似于数学中的集合,也可以求交集,求并集等,''' s1={1,2,3,1} #定义一个set s1 如果s1={}为空则默认定义一个字 ...

  10. ASCII、Unicode、utf-8、utf-16、utf-32

    理解ASCII.Unicode.utf-8.utf-16.utf-32 目录 理解ASCII.Unicode.utf-8.utf-16.utf-32编码与解码字符集字符编码ASCIIUnicodeUT ...