线程全局修改、死锁、递归锁、信号量、GIL以及多进程和多线程的比较
线程全局修改
x = 100
def func1():
global x
print(x)
changex()
print(x)
def changex():
global x
x = 50
func1()
"""
100
50
"""
线程锁
from threading import Thread, Lock
x = 0
mutex = Lock()
def task():
global x
mutex.acquire() #加了锁之后就能保证每次只有一个运行,就不会出现数据丢失现象,不过效率会降低
for i in range(100000):
x = x + 1
"""
如果不加锁,那么(以下的情况属于假设):
t1 的 x 刚拿到0(属于IO) 保存好状态,这时候CPU切换给t2运行。
t2 的 x拿到 0 并进行+1 操作 这时候x是1(运行完CPU切换)
t1 又获得运行了 x = 0 并进行+1操作 这时候x也是1
****************************
经过上面三步,是加了2次1,而真实运算出来的应该是+2,实际上只是加了1
这就是为什么不加锁本来应该是300000,但是实际上却小于这个数的原因
这就会产生数据安全问题
"""
mutex.release()
if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t3 = Thread(target=task)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(x)
死锁问题
from threading import Thread,Lock
lock1 = Lock()
# lock2 = lock1 #这种情况相当于只有一把锁,
# 所以抢到了锁1之后没办法再抢锁2了,就会卡在(Thread-1 抢到了锁1)
lock2 = Lock()
class DeadLock(Thread):
def run(self):
self.task1()
self.task2()
def task1(self):
lock1.acquire()
print(f'{self.name} 抢到了锁1')
lock2.acquire()
print(f'{self.name} 抢到了锁2')
lock2.release()
print(f'{self.name} 释放了锁2')
lock1.release()
print(f'{self.name} 释放了锁1')
def task2(self):
# 这里如果抢锁2,就会出现死锁现象,就会卡在这
# lock2.acquire()
# print(f'{self.name} 抢到了锁2')
# 这里如果抢锁1,就不会出现死锁现象,会一直运行下去
# lock1.acquire()
# print(f'{self.name} 抢到了锁1')
lock2.acquire()
print(f'{self.name} 抢到了锁2')
lock1.release()
print(f'{self.name} 释放了锁1')
lock2.release()
print(f'{self.name} 释放了锁2')
for i in range(3):
t = DeadLock()
t.start()
*******死锁问题********
###两个线程
# 线程1拿到了(锁2),想要往下执行需要(锁1),
# 线程2拿到了(锁1),想要往下执行需要(锁2),
# 互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁
递归锁
from threading import Thread,RLock
'''
递归锁 在同一个线程内可以被多次acquire
如何释放 内部相当于维护了一个计数器
也就是说同一个线程 acquire了几次
就要release几次
'''
lock1 = RLock()
lock2 = lock1
class Recursion(Thread):
def run(self):
self.task1()
self.task2()
def task1(self):
lock1.acquire()
print(f'{self.name}抢到了 锁1')
lock2.acquire()
print(f'{self.name}抢到了 锁2')
lock1.release()
print(f'{self.name}释放了 锁1')
lock2.release()
print(f'{self.name}释放了 锁2')
def task2(self):
lock1.acquire()
print(f'{self.name}抢到了 锁1')
lock2.acquire()
print(f'{self.name}抢到了 锁2')
lock1.release()
print(f'{self.name}释放了 锁1')
lock2.release()
print(f'{self.name}释放了 锁2')
for i in range(3):
t = Recursion()
t.start()
#可以正常执行,不会出现差错
信号量
from threading import Thread,currentThread,Semaphore
import time
def task():
sm.acquire()
time.sleep(2)
print(f'{currentThread().name} is running!')
sm.release()
sm = Semaphore(5) #(可以一次性发5个,信号量就是自定义最大连接数5个)
for i in range(15):
t = Thread(target=task)
t.start()
"""
会分3组,
每组5个打印出来
"""
GIL(全局解释器锁)
"""
###在Cpython解释器中有一把GIL(全局解释器锁),GIL锁本质是一把互斥锁。
导致了同一个进程下,同一时间只能运行一个进程,无法利用多核优势,同一进程
下多个线程只能实现并发不能实现并行。
为什么要有GIL?
因为Cpython自带的垃圾回收机制不是线程安全的,所以要有GIL锁。
导致了同一进程下,同一时间只能运行一个线程,无法利用多核优势。
分析:
我们有四个任务需要处理,处理方式肯定要玩出并发的效果,解决方案可以是:
方案一:开启四个进程
方案二:一个进程下,开启四个线程
"""
#******计算密集型******
#推荐使用多进程
from threading import Thread
from multiprocessing import Process
import time
def work1():
res = 0
for i in range(100000000):
res *= i
if __name__ == '__main__':
t_list = []
start = time.time()
for i in range(5):
t = Process(target=work1)
# t = Thread(target=work1())
t.start()
t_list.append(t)
for t in t_list:
t.join()
end = time.time()
print('多进程', end - start) #多进程 22.06749701499939
# print('多线程', end - start) #多线程 41.195727586746216
******IO密集型******
#推荐使用多线程
from threading import Thread
from multiprocessing import Process
import time
def task1():
x = 1+1
time.sleep(3)
if __name__ == '__main__':
t_list = []
start = time.time()
for i in range(4):
# t = Thread(target=task1)
t = Process(target=task1)
t_list.append(t)
t.start()
for t in t_list:
t.join()
end = time.time()
# print('多线程', end - start) #多线程 3.002215623855591
print('多进程', end - start) #多进程 3.8354334831237793
线程全局修改、死锁、递归锁、信号量、GIL以及多进程和多线程的比较的更多相关文章
- python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03
目录 结合多线程实现服务端并发(不用socketserver模块) 服务端代码 客户端代码 CIL全局解释器锁****** 可能被问到的两个判断 与普通互斥锁的区别 验证python的多线程是否有用需 ...
- 并发编程---死锁||递归锁---信号量---Event事件---定时器
死锁 互斥锁:Lock(),互斥锁只能acquire一次 递归锁: RLock(),可以连续acquire多次,每acquire一次计数器+1,只有计数为0时,才能被抢到acquire # 死锁 f ...
- 同步锁 死锁与递归锁 信号量 线程queue event事件
二个需要注意的点: 1 线程抢的是GIL锁,GIL锁相当于执行权限,拿到执行权限后才能拿到互斥锁Lock,其他线程也可以抢到GIL,但如果发现Lock任然没有被释放则阻塞,即便是拿到执行权限GIL也要 ...
- 线程锁&信号量&gil
线程锁 线程锁的主要目的是防止多个线程之间出现同时抢同一个数据,这会造成数据的流失.线程锁的作用类似于进程锁,都是为了数据的安全性 下面,我将用代码来体现进程锁的作用: from threading ...
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- 并发编程~~~多线程~~~守护线程, 互斥锁, 死锁现象与递归锁, 信号量 (Semaphore), GIL全局解释器锁
一 守护线程 from threading import Thread import time def foo(): print(123) time.sleep(1) print('end123') ...
- GIL全局解释器锁-死锁与递归锁-信号量-event事件
一.全局解释器锁GIL: 官方的解释:掌握概念为主 """ In CPython, the global interpreter lock, or GIL, is a m ...
- day 7-6 GIL,死锁,递归锁与信号量,Event,queue,
摘要: 1.死锁与递归锁 2.信号量 3.Event 4.Timer 5.GIL 6.Queue 7.什么时候该用多线程和多进程 一. 死锁与递归锁 所谓死锁: 是指两个或两个以上的进程或线程在执行过 ...
- python 线程(创建2种方式,锁,死锁,递归锁,GIL锁,守护进程)
###############总结############ 线程创建的2种方式(重点) 进程:资源分配单位 线程:cpu执行单位(实体) 线程的创建和销毁的开销特别小 线程之间资源共享,是同一个 ...
随机推荐
- 用 cgroups 管理 cpu 资源
转自:http://xiezhenye.com/2013/10/用-cgroups-管理-cpu-资源.html 这回说说怎样通过 cgroups 来管理 cpu 资源.先说控制进程的 cpu 使用. ...
- 认识beanstalkd
认识beanstalkd 背景 公司业务做某个需求是将数据写入到消息队列中,然后另外一个服务来消费数据,这里的消息队列使用的是beastalkd,之前接触到的消息队列为kafka,因此简单学习记录一 ...
- SpringBoot 第一篇:入门篇
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10819728.html 版权声明:本文为博主原创文章,转载请附上博文链接! 前言 博主从去年 ...
- Java并发之原子性,可见性,有序性
原子性 原子性指的是一个或者多个操作在 CPU 执行的过程中不被中断的特性 在多线程情况下,线程会被操作系统调度进行任务切换,占有CPU时间片段的就执行,否则就阻塞 java中对基础类型的变量赋值是 ...
- mybatis 报Invalid bound statement(not found) 和 Property 'mapperLocations' was not specified or not matching resources found
排除问题的步骤: 1.首先检查mapper文件和mapper接口的文件名是否相等. 2.pom.xml是否把xml排除了,这样写就会src/main/java下所有的Mybatis的xml文件都删除, ...
- Prometheus 安装Alertmanager集成
Prometheus 安装Alertmanager集成 # 下载地址 地址1:https://prometheus.io/download/ 地址2:https://github.com/promet ...
- python]用eval强制将字符串转换为字典变量时候出错:NameError: name 'null' is not defined[python]用eval函数 字符串转dict
本博客已搬家至个人网站 在路上 - On the way 下面的 技术 分类. 你可以通过点击 更新帖子 [已解决]Python中,用eval强制将字符串转换为字典变量时候出错:NameError: ...
- VS.NET(C#)--2.4_aspx默认页面模板代码
默认模板代码 客户端浏览器将忽视<script>块间任何字符,不在页面输出.通过<%=DataTime.Now.ToString() %> 将服务端代码放中间 < ...
- 02 .NET CORE 2.2 使用OCELOT -- 路由
继续学习.NET CORE 2.2 使用OCELOT https://www.jianshu.com/p/05ccf87a3091 https://www.jianshu.com/p/585396dc ...
- c#专业的UVC摄像头深控类库-SharpCamera介绍
SharpCamera是专业的UVC摄像头深控类库.允许您在C#代码内修改摄像头的高级参数,比如亮度.对比度.清晰度.色调.饱和度.伽玛值.白平衡.逆光对比.增益.缩放.焦点.曝光.光圈.全景.倾斜. ...