多线程--GIL锁
GIL
即全局解释器锁,是一个互斥锁,防止多个线程在同一时间执行python代码,因为在一个python进程中,不仅有主线程而且还有该主线程开启的子线程,还有解释器开启的垃圾回收机等解释器级别的线程。因为所有的代码都是共享的,所以垃圾回收线程也可能同时访问到解释器的代码去执行,所以解决这一问题的方法就是GIL,以保证python解释器同一时间只能执行同一个任务的代码。
GIL带来的问题
执行一个py文件,分为三个步骤:
- 从硬盘加载python解释器到内存
- 从硬盘加载py文件到内存
- 解释器解析py文件内容,交给CPU执行
需要明确的是每当执行一个py文件,就会立即启动一个python解释器
GIL是CPython解释器独有的,它将线程的并行变为串行,导致效率降低。
GIL对于性能的影响
- 单核下无论IO密集型还是计算密集型GIL都不会产生任何影响
- 多核下对于IO密集型任务,GIL会有细微影响,基本可以忽略
- CPython中IO密集型任务应该采用多线程,计算密集型应该采用多进程
另外:之所以广泛采用CPython解释器,就是因为大量的应用程序都是IO密集型的,还有另一个很重要的原因是CPython可以无缝对接各种C语言实现的库,这对于一些数学计算相关的应用程序而言非常的happy,直接就能使用各种现成的算法
自定义的线程锁和GIL的区别
GIL保护的是解释器级别的数据安全,比如对象的引用计数,垃圾回收机制等
对于程序中自己定义的数据则没有任何保护效果
from threading import Thread,Lock
import time
a = 0
def task():
global a
temp = a
time.sleep(0.01)
a = temp + 1
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
t1.join()
t2.join()
print(a)
#1
过程分析:
1.线程1获得CPU执行权,并获取GIL锁执行代码 ,得到a的值为0后进入睡眠,释放CPU并释放GIL
2.线程2获得CPU执行权,并获取GIL锁执行代码 ,得到a的值为0后进入睡眠,释放CPU并释放GIL
3.线程1睡醒后获得CPU执行权,并获取GIL执行代码 ,将temp的值0+1后赋给a,执行完毕释放CPU并释放GIL
4.线程2睡醒后获得CPU执行权,并获取GIL执行代码 ,将temp的值0+1后赋给a,执行完毕释放CPU并释放GIL,最后a的值也就是1
之所以出现问题是因为两个线程在并发的执行同一段代码,解决方案就是加锁!
from threading import Thread,Lock
import time
lock = Lock()
a = 0
def task():
global a
lock.acquire()
temp = a
time.sleep(0.01)
a = temp + 1
lock.release()
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
t1.join()
t2.join()
print(a)
#2
过程分析:
1.线程1获得CPU执行权,并获取GIL锁执行代码 ,得到a的值为0后进入睡眠,释放CPU并释放GIL,不释放lock
2.线程2获得CPU执行权,并获取GIL锁,尝试获取lock失败,无法执行,释放CPU并释放GIL
3.线程1睡醒后获得CPU执行权,并获取GIL继续执行代码 ,将temp的值0+1后赋给a,执行完毕释放CPU释放GIL,释放lock,此时a的值为1
4.线程2获得CPU执行权,获取GIL锁,尝试获取lock成功,执行代码,得到a的值为1后进入睡眠,释放CPU并释放GIL,不释放lock
5.线程2睡醒后获得CPU执行权,获取GIL继续执行代码 ,将temp的值1+1后赋给a,执行完毕释放CPU释放GIL,释放lock,此时a的值为2
即
多线程--GIL锁的更多相关文章
- 并发编程-多线程,GIL锁
本章内容: 1.什么是GIL 2.GIL带来的问题 3.为什么需要GIL 4.关于GIL的性能讨论 5.自定义的线程互斥锁与GIL的区别 6.线程池与进程池 7.同步异步,阻塞非阻塞 一.什么是GIL ...
- python爬虫之多线程、多进程、GIL锁
背景: 我们知道多线程要比多进程效率更高,因为线程存在于进程之内,打开一个进程的话,首先需要开辟内存空间,占用内存空间比线程大.这样想也不怪,比如一个进程用10MB,开10个进程就得100MB的内存空 ...
- [Python 多线程] GIL全局解释器锁 (十三)
Queue 标准库queue模块,提供FIFO(先进先出)的Queue.LIFO(后进先出)的队列.优先队列. Queue类是线程安全的,适用于多线程间安全的交换数据.内部使用了Lock和Condit ...
- 网络编程之多线程——GIL全局解释器锁
网络编程之多线程--GIL全局解释器锁 一.引子 定义: In CPython, the global interpreter lock, or GIL, is a mutex that preven ...
- python笔记9 线程进程 threading多线程模块 GIL锁 multiprocessing多进程模块 同步锁Lock 队列queue IO模型
线程与进程 进程 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数据集则是程序在执行过程中所需要 ...
- [并发编程 - 多线程:信号量、死锁与递归锁、时间Event、定时器Timer、线程队列、GIL锁]
[并发编程 - 多线程:信号量.死锁与递归锁.时间Event.定时器Timer.线程队列.GIL锁] 信号量 信号量Semaphore:管理一个内置的计数器 每当调用acquire()时内置计数器-1 ...
- Python的多线程GIL浅谈
来源知乎:https://www.zhihu.com/question/23474039/answer/269526476 在介绍Python中的线程之前,先明确一个问题,Python中的多线程是假的 ...
- 53_并发编程-线程-GIL锁
一.GIL - 全局解释器锁 有了GIL的存在,同一时刻同一进程中只有一个线程被执行:由于线程不能使用cpu多核,可以开多个进程实现线程的并发,因为每个进程都会含有一个线程,每个进程都有自己的GI ...
- python 线程(创建2种方式,锁,死锁,递归锁,GIL锁,守护进程)
###############总结############ 线程创建的2种方式(重点) 进程:资源分配单位 线程:cpu执行单位(实体) 线程的创建和销毁的开销特别小 线程之间资源共享,是同一个 ...
随机推荐
- QT开发资料
QT开发入门资料 https://tmr.js.org/p/cc37608/ QT学习之路: https://www.devbean.net/
- 利用字节流文件生成包含多文件的zip文件
InputStream[] inputStreamsList = new InputStream[jsonArr.size()]; String[] fileNameList = new String ...
- Number 的扩展
Number.parseInt(), Number.parseFloat() ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变. Numb ...
- 【转】硬盘分区知识介绍(MBR)
转自:http://www.blogjava.net/galaxyp/archive/2010/04/25/319344.html 硬盘是现在计算机上最常用的存储器之一.我们都知道,计算机之所以神奇, ...
- Springboot文件上传限制
#100,000,000 100M spring.servlet.multipart.max-file-size = 100000000 spring.servlet.multipart.max-re ...
- delphi窗体透明但上面的控件不透明怎么实现
我不知道LAZARUS是什么玩意.纯用DELPHI的话.procedure TForm1.FormCreate(Sender: TObject);var mStyle, mExStyle: Longi ...
- NX二次开发-UFUN打开信息窗口UF_UI_open_listing_window()
NX9+VS2012 #include <uf.h> #include <uf_ui.h> UF_initialize(); //方法1(uc1601) uc1601();// ...
- idea使用问题
1. 问题: 突发断电导致idea的play项目错误,无法识别build.sbt,build.sbt文件报错,Cannot resolve symbol 解决方案: For anyone having ...
- 2019 牛客多校第六场 J Upgrading Technology
题目链接:https://ac.nowcoder.com/acm/contest/886/J 题目大意 略. 分析 见代码. 代码如下 #include <bits/stdc++.h> u ...
- 如何理解CUDA中的cudaMalloc()的参数
首先看下此运行时函数的原型: cudaError_t cudaMalloc (void **devPtr, size_t size ); 主要的第一个参数.为什么是两个星星呢?用个例子来说明下. fl ...