'''
定义:
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解释器解释之后才能被cpu执行
- 同一时刻同一个进程内多个线程无法实现并行,但是可以实现并发

  一.GIL全局解释器 垃圾回收机制:

- 垃圾回收机制也是一个任务,跟你的代码不是串行运行,如果是串行会明显有卡顿
- 这个垃圾回收到底是开进程还是开线程?肯定是线程,线程肯定也是一段代码,所以想运行也必须要拿到python解释器
没有GIL全局解释器锁 他只是对线程加锁 不是对数据
运行垃圾回收机制:引用计数 1,必须先拿到python 解释器---> 2.python 进程下的多个线程是并发。若此时你想创建一个 a = 1 cpu运行速度是非常快的
那么就会引发 其他线程垃圾回收机制扫描把我刚创建的内存清理掉 所以必须设置GIL全局解释器锁
也就意味着在Cpython解释器上有一把GIL全局解释器锁

 二. 

1.python中的多线程到底有没有用?
  一、数据密集型
  二、IO密集型
#### 1.python中的多线程到底有没有用?

单核情况下:四个任务

多核情况下:四个任务

计算密集型:一个任务算十秒,四个进程和四个线程,肯定是进程快

IO密集型:任务都是纯io情况下,线程开销比进程小,肯定是线程好
一、数据密集型
def task():
res = 0
for i in range(100000000):
res = res*i if __name__ == '__main__':
print(os.cpu_count()) #本机内核
p_list=[]
start_time= time.time()
for i in range(4):
p = Process(target=task) # 进程运行时间为10.636553287506104
# p = Thread(target= task) # 线程运行时间为19.97660756111145
p.start()
p_list.append(p)
for p in p_list:
p.join()
end_time = time.time()
print('运行时间为%s'% (end_time-start_time))

  

""
二、IO密集型
def work():
time.sleep(3)
if __name__ == '__main__':
print(os.cpu_count())
start_time =time.time()
p_list=[]
for i in range(4):
# p = Process(target= work) # run is total_time7.271259546279907
p = Thread(target= work) # run is total_time3.002392053604126
p.start()
p_list.append(p)
for p in p_list:
p.join()
end_time =time.time()
print('run is total_time%s'%(end_time-start_time))

  三、全局锁与普通锁

  

对于不同的数据,要想保证安全,需要加不同的锁处理
GIL并不能保证数据的安全,它是对Cpython解释器加锁,针对的是线程
保证的是同一个进程下多个线程之间的安全

  

"""
from threading import Thread import os
import time
from threading import Lock
mutex = Lock()
num = 100
def task():
global num
mutex.acquire() #抢锁
temp = num
time.sleep(0.1)
num = temp-1
mutex.release() # 释放锁 开始一个 if __name__ == '__main__':
p_lsit=[]
for i in range(10): p = Thread(target=task)
p.start()
p_lsit.append(p)
for p in p_lsit:
p.join()
print(num) # 90 相当于10个线程同时去抢100票 必须要确保一个数据同时被10个进程同时抢 锁是起到保护作用 取完一个减一个

  四、.死锁与递归锁(了解)

自定义锁一次acquire必须对应一次release,不能连续acquire

递归锁可以连续的acquire,每acquire一次计数加一

import time
from threading import Thread,RLock mutexA = mutexB= RLock() # 递归锁RLock
class Mythread(Thread): def run(self):
self.fn1()
self.fn2() def fn1(self):
#设置锁
mutexA.acquire()
print('%s 抢到A锁了'%self.name)
mutexB.acquire()
print('%s 抢到B锁了'%self.name)
mutexB.release()
print('%s释放了B锁'%self.name)
mutexA.release()
print('%s释放了A锁'%self.name) def fn2(self):
mutexB.acquire()
print('%s 抢到A锁了' % self.name)
time.sleep(1)
mutexA.acquire()
print('%s 抢到B锁了' % self.name)
mutexA.release()
print('%s释放了B锁' % self.name)
mutexB.release()
print('%s释放了A锁' % self.name) if __name__ == '__main__':
for i in range(100):
t = Mythread()
t.start()

  

五.Event事件

一些线程需要等待另外一些线程运行完毕才能运行,类似于发射信号一样

from threading import Thread

from threading import Event

import time
event = Event() #造了一个绿灯
def light():
print('等红灯')
time.sleep(3)
event.set() # 解除阻塞并且给 event发了一个信号
print('绿灯亮了') def car(i):
print('%s灯红灯'%i)
event.wait()
print('%s绿灯了,加油门'%i) if __name__ == '__main__':
t = Thread(target=light)
t.start() p_list=[]
for i in range(5):
p = Thread(target=car,args=(i,))
p.start() # 等红灯
# 0灯红灯
# 1灯红灯
# 2灯红灯
# 3灯红灯
# 4灯红灯
# 绿灯亮了
# 0绿灯了,加油门
# 1绿灯了,加油门
# 3绿灯了,加油门
# 4绿灯了,加油门
# 2绿灯了,加油门#

  

六.信号量(了解)

自定义的互斥锁如果是一个厕所,那么信号量就相当于公共厕所,门口挂着多个厕所的钥匙。抢和释放跟互斥锁一致

普通互斥锁, 独立卫生间 所有人只有一把锁
信号量 ,公共卫生间 有多少个坑 就有多少把锁
"""
from threading import Thread
from threading import Semaphore #信号量
import time
import random
sm = Semaphore(5) #一个公共厕所造了5个坑 在厕所外放了5把锁 def task(name):
sm.acquire() # 释放信号锁 print('%s正在蹲坑'%name)
time.sleep(random.randint(1, 3))
sm.release() for i in range(20):
t = Thread(target= task,args=('%s伞兵'%i,))
t.start()

 

0伞兵正在蹲坑
1伞兵正在蹲坑
2伞兵正在蹲坑
3伞兵正在蹲坑
4伞兵正在蹲坑
此时5个人中 有一个人好了 同时释放了一把锁
5伞兵正在蹲坑
前面5个好了两个释放给 6,7
6伞兵正在蹲坑
7伞兵正在蹲坑 8伞兵正在蹲坑
9伞兵正在蹲坑
10伞兵正在蹲坑
11伞兵正在蹲坑 12伞兵正在蹲坑
13伞兵正在蹲坑
14伞兵正在蹲坑
15伞兵正在蹲坑 16伞兵正在蹲坑
17伞兵正在蹲坑
18伞兵正在蹲坑
19伞兵正在蹲坑

  

  

七.线程queue

同一个进程下的线程数据都是共享的为什么还要用queue?queue本身自带锁的功能,能够保证数据的安全

  

import queue

"""
1.普通q
2.堆栈。先进后出q
3.优先级q """
q = queue.Queue(3)
q.put(1)
q.put(2) q.put(3)
print(q.get())
print(q.get())
print(q.get()) # 取值
——————》》》
1
2
3 q = queue.LifoQueue(5)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
q.put(5) print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get()) # 先进后出 和堆栈一样
——————》》》

5
4
3
2
1

q = queue.PriorityQueue(3)
q.put(100,"q")
q.put(20,"t")
q.put(-1,'s') print(q.get())
print(q.get())
print(q.get()) # 优先级是按照数字从小到大排列的
————————》》》

-1
20
100

  

  

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

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

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

  2. python 全局解释锁GIL

    Python的全局解释器锁GIL用于保护python解释器,使得任意时刻,只有一个线程在解释器中运行.从而保证线程安全 在多线程环境中,Python 虚拟机按以下方式执行: 1. 设置GIL2. 切换 ...

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

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

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

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

  5. 20191031:GIL全局解释锁

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

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

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

  7. python 线程队列、线程池、全局解释器锁GIL

    一.线程队列 队列特性:取一个值少一个,只能取一次,没有值的时候会阻塞,队列满了,也会阻塞 queue队列 :使用import queue,用法与进程Queue一样 queue is especial ...

  8. 并发编程——全局解释器锁GIL

    1.全局解释器锁GIL GIL其实就是一把互斥锁(牺牲了效率但是保证了数据的安全). 线程是执行单位,但是不能直接运行,需要先拿到python解释器解释之后才能被cpu执行 同一时刻同一个进程内多个线 ...

  9. 你是否真的了解全局解析锁(GIL)

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

随机推荐

  1. Java基础之方法详解

    方法的所属性 在Java的语言中,方法相当于C语言中的函数,但是它与传统的函数也有着明确的不同:在结构化的语言中,函数是一等公民,整个程序是由一个个函数组成的:但是在面向对象的语言里,类是一等公民,整 ...

  2. 微信小程序之登录用户不是该小程序的开发者

    当uniapp项目转为小程序项目的时候,预览会显示“您不是登录用户...”,所以没有办法发布,这个时候打开“project.config.json”设置一下appid,与你公众号appid一致就可以

  3. 任何国家都无法限制数字货币。为什么呢? 要想明白这个问题需要具备一点区块链的基础知识: 区块链使用的大致技术包括以下几种: a.点对点网络设计 b.加密技术应用  c.分布式算法的实现 d.数据存储技术 e.拜占庭算法 f.权益证明POW,POS,DPOS 原因一: 点对点网络设计 其中点对点的P2P网络是bittorent ,由于是点对点的网络,没有中心化,因此在全球分布式的网

    任何国家都无法限制数字货币.为什么呢? 要想明白这个问题需要具备一点区块链的基础知识: 区块链使用的大致技术包括以下几种: a.点对点网络设计 b.加密技术应用  c.分布式算法的实现 d.数据存储技 ...

  4. Apache2.4+PHP7.2环境搭建

    Editplus生成码:http://www.jb51.net/tools/editplus/ 阿帕奇下载地址:https://www.apachehaus.com/cgi-bin/download. ...

  5. vim推荐的光标移动配置文件?

    http://roclinux.cn/?p=1466 inoremap jk inoremap ... 参考较好的vim设置文件 : 共享粘贴板: set clipboard+=unnamed 除了映 ...

  6. DRF中的视图集的使用

    1.说明:DRF框架中的视图集: 在drf开发接口中,使用GenericAPIView和视图扩展类结合起来完成接口功能是一件很常见的事情,所以,drf的作者帮我们提前把  GenericAPIView ...

  7. 使用GOGS搭建自己的Git托管

    大家在开发中一般使用的git服务都是公司搭建好的,或者就是直接用gayhub提供的免费的仓库 如果想搭建一个自己的仓库的话怎么弄,这里给大家安利一款开箱即用的git托管服务:gogs. gogs是基于 ...

  8. vue-methods方法与computed计算属性的差别

    好吧,我就是单纯的举个例子:实现显示变量 message 的翻转字符串 第一种:methods:我们可以通过在表达式中调用方法来达到同样的效果: 第二种:computed:计算属性 上面的2中方法都实 ...

  9. [LeetCode] 834. Sum of Distances in Tree

    LeetCode刷题记录 传送门 Description An undirected, connected treewith N nodes labelled 0...N-1 and N-1 edge ...

  10. 解锁 HTTPS原理

    From今日头条:https://www.toutiao.com/a6534826865792647693/?tt_from=weixin&utm_campaign=client_share& ...