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.
大译:
python解释器有很多种  最常见的就是Cpython解释器
GIL本质也是一把互斥锁:将并发变成串行牺牲效率保证数据的安全
用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发)
GIL的存在是因为CPython解释器的内存管理不是线程安全的,这种不安全是来自于垃圾回收机制,每个进程下都会有一个内存管理线程

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

所有线程的任务,都需要将代码传给解释器去执行,所以首先要解决的是能够访问到解释器代码
如果多个线程的target = work name执行流程是:

多个线程先访问到解释器的代码,即拿到执行权限,然后将target的代码交给解释器的代码执行,解释器的代码是所有线程共享的,所以来及回收线程也可能访问到解释器的代码而去执行,
这就导致了一个问题:对于共一个数据 100,在线程1执行x = 100的同时,垃圾回收机制执行的是回收100的操作,所以需要通过添加GIL锁,保证python解释器同一时间只能执行一个任务代码

问题: python的多线程没法利用多个优势,是不是就没用了

答: 研究python的多线程是否有用需要分情况讨论

例:

1.四个计算密集型任务, 每个10s

单核情况:

开线程更省资源

多核情况:

开进程 10s

开线程 40s

2.四个IO密集型任务, 每个10s

单核情况:

开线程更省资源

多核情况:

开线程更省资源
from multiprocessing import Process
from threading import Thread
import time, os

# 计算密集型
def func():
res = 0
for i in range(10000):
res *= 1

# IO 密集型
def func():
time.sleep(3)

if __name__ == '__main__':
print(os.cpu_count())
list = []
start = time.time()
for i in range(4):
p = Process(target=func) # 多进程
# 计算密集型运行时间:0.21994638442993164
# IO密集型运行时间:3.2253575325012207
p = Thread(target=func) # 多线程
# 运行时间:0.003988504409790039
# IO密集型运行时间:3.0033791065216064
list.append(p)
p.start()
for p in list:
p.join() # 等待所有子进程/子线程运行结束后再运行主进程/主线程
end = time.time()
print('运行时间:%s'%(end - start))

死锁/递归锁

指的是两个进程或线程在执行的过程中,因争抢资源而造成的一种互相等待的现象.

注意: 自己千万不要轻易处理锁

Rlock 递归锁

Rlock可以被第一个抢到锁的人连续的acquire和release
每acquire一次,锁身上的计数加一
每release一个,锁身上的计数减一
只要锁的计数不为0,其他进程/线程都不能抢
from threading import Thread, Lock
import time


# 生成两把锁
mutexA = Lock()
mutexB = Lock()

class MyThread(Thread):
def run(self):
self.func1()
self.func2()

def func1(self):
mutexA.acquire()
print('%s抢到了A锁'%self.name) # self.name 等价于 current_thread(),name
mutexB.acquire()
print('%s抢到了B锁' % self.name)
mutexB.release()
print('%s释放了B锁' % self.name)
mutexA.release()
print('%s释放了A锁' % self.name)

def func2(self):
mutexB.acquire()
print('%s抢到了B锁' % self.name)
time.sleep(1)
mutexA.acquire()
print('%s抢到了A锁' % self.name)
mutexA.release()
print('%s释放了A锁' % self.name)
mutexB.release()
print('%s释放了B锁' % self.name)

for i in range(10):
t = MyThread()
t.start()

# 递归锁
from threading import Thread, RLock

mutexA = mutexB = RLock()

class MyThread(Thread):
def run(self):
self.func1()
self.func2()

def func1(self):
mutexA.acquire()
print('%s抢到了A锁'%self.name) # self.name 等价于 current_thread(),name
mutexB.acquire()
print('%s抢到了B锁' % self.name)
mutexB.release()
print('%s释放了B锁' % self.name)
mutexA.release()
print('%s释放了A锁' % self.name)

def func2(self):
mutexB.acquire()
print('%s抢到了B锁' % self.name)
time.sleep(1)
mutexA.acquire()
print('%s抢到了A锁' % self.name)
mutexA.release()
print('%s释放了A锁' % self.name)
mutexB.release()
print('%s释放了B锁' % self.name)

for i in range(10):
t = MyThread()
t.start()

信号量

互斥锁: 一把锁一把钥匙
信号量: 一把锁多把钥匙
from threading import Thread, Semaphore
import time
import random

sem = Semaphore(5) # 生成一把锁五把钥匙

def func(name):
sem.acquire()
print('%s进门了'%name)
time.sleep(random.randint(1, 3))
sem.release()
print('%s出门了'%name)

for i in range(10):
t = Thread(target=func, args=(i, ))
t.start()

event事件

e.set() 发信号
e.wait() 等待信号
from threading import Thread, Event
import time


e = Event()
def light():
print('红灯')
time.sleep(3)
e.set()
print('绿灯')

def car(name):
print('%s等红灯'%name)
e.wait()
print('%s开车了'%name)

t = Thread(target=light)
t.start()

for i in range(10):
t = Thread(target=car, args=('车手%i'%i, ))
t.start()

线程queue

同一个进程下的多个线程本来就是数据共享,为什么还要用队列?
因为队列是 管道+锁,使用队列就不需要自己动手操作锁的问题
import queue

q = queue.Queue()
q.put('one')
q.put('two')
q.put('three')
print(q.get()) # >>> one 先进先出

q = queue.LifoQueue()
q.put('one')
q.put('two')
q.put('three')
print(q.get()) # >>> three 堆栈 先进后出

q = queue.PriorityQueue() # 数字越小,优先级越高
q.put((10, 'one'))
q.put((1, 'two'))
q.put((5, 'three'))
print(q.get()) # >>> (1, 'two')

GIL 信号量 event事件 线程queue的更多相关文章

  1. python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03

    目录 结合多线程实现服务端并发(不用socketserver模块) 服务端代码 客户端代码 CIL全局解释器锁****** 可能被问到的两个判断 与普通互斥锁的区别 验证python的多线程是否有用需 ...

  2. 8.14 day32 TCP服务端并发 GIL解释器锁 python多线程是否有用 死锁与递归锁 信号量event事件线程q

    TCP服务端支持并发 解决方式:开多线程 服务端 基础版 import socket """ 服务端 1.要有固定的IP和PORT 2.24小时不间断提供服务 3.能够支 ...

  3. 并发编程---死锁||递归锁---信号量---Event事件---定时器

    死锁 互斥锁:Lock(),互斥锁只能acquire一次 递归锁:  RLock(),可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire # 死锁 f ...

  4. 线程 Thread类 GIL锁 信号量 Event事件

    线程的开启方法 进程是操作系统调度的最小单位,一个进程最少有一个主线程,而一个进程中可以开启多个线程 from threading import Thread def task(): print('A ...

  5. GIL全局解释器锁-死锁与递归锁-信号量-event事件

    一.全局解释器锁GIL: 官方的解释:掌握概念为主 """ In CPython, the global interpreter lock, or GIL, is a m ...

  6. GIL与event事件讲解

    一.GIL全局解释器锁 global interpreter lock 1.GIL是一个互斥锁:保证数据的安全(以牺牲效率来换取数据的安全),阻止同一个进程内多个线程同时执行(不能并行但是能够实现并发 ...

  7. (并发编程)RLock(与死锁现象),Semaphore,Even事件,线程Queue

    一.死锁现象与递归锁所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在 ...

  8. 人生苦短之我用Python篇(线程/进程、threading模块:全局解释器锁gil/信号量/Event、)

    线程: 有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.是一串指令的集合.线程是程序中一个单一的顺序控制流程.进程内一个相对独立的.可调度的执行单元,是 ...

  9. Python 36 死锁现象和递归锁、信号量、Event事件、线程queue

    一:死锁现象和递归锁 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远 ...

随机推荐

  1. Scratch编程:多彩的舞台(六)

    “ 上节课的内容全部掌握了吗?反复练习了没有,编程最好的学习方法就是练习.练习.再练习.一定要记得多动手.多动脑筋哦~~” 01 — 游戏介绍 这是一款简单的小游戏,实现了一个小女孩在多彩的舞台上进行 ...

  2. PowerBuilder学习笔记之2PowerScript语言(三)

    教材地址:https://wenku.baidu.com/view/1e82d26925c52cc58ad6be05.html?sxts=1565679996440 2.6嵌入式SQL语句 2.6.1 ...

  3. Feign 客户端调用错误

    1.@RequestBody 必须要写在实现接口中 2.Feign 客户端调用的时候如果有参数的话,默认是发送post请求 3.服务接口中的请求参数必须要加上@RequestParam("r ...

  4. 本地计算机上的mysql服务启动停止后,某些服务在未由其他服务或程序使用时将自动停止

    C:\Windows\system32>cd C:\Program Files\mysql-8.0.18-winx64\bin\ C:\Program Files\mysql-8.0.18-wi ...

  5. javascript获取url参数的方式

     方式一: 推荐使用此方式: url链接为:newsDetail.html?id=8a8080e35f90d9fd015f90dac7750001&modelId=123456 var URL ...

  6. vue+axios通过formdata提交参数和上传文件

    demo.vue 文件 <template> <div class="demo"> <input v-model="importForm.m ...

  7. 一次实战CTF-WEB(多重登录机制中的缺陷)

    要求登录admin账号 1.登录界面 我们发现有找回密码这个易受攻击点 2.直奔找回密码 通过观察前两个阶段url(reset1.htm1 reset2.html),我们推测出了第三个阶段的url(r ...

  8. nginx 反向代理配置(二)

    上一篇文章主要是对 nginx 各个模块做了一个介绍,以及对什么是反向代理在文章开头做了一个简单介绍,这篇文章我们主要来看下如何进行 nginx 反向代理的配置 proxy 模块      nginx ...

  9. requests模块的基本用法

    requests 什么是requests模块 python中封装好的一个基于网络请求的模块 作用 用来模拟浏览器发送请求 环境安装 pip install requests 编码流程 指定 url 发 ...

  10. vue锚点

    第一种: router.js中添加 mode: 'history', srcollBehavior(to,from,savedPosition){ if(to.hash){ return { sele ...