4,GIL全局解释器锁,event事件,信号量
今日内容
1,GIL全局解释器锁
2,死锁
3,信号量
4,event事件
5,队列
一:GIL全局解释器锁
什么是GIL 全局解释器锁:
它的本质也是一把互斥锁,是在CPython解释器锁,将并发变为串行的,
牺牲效率,保证数据安全性!
作用:用来阻止同一个进程下的多个线程的同时执行
(同一个进程内多个线程无法实现并行但是可以实现并发)
GIL的存在是因为CPython解释器的内存管理不是线程安全的
研究python的多线程是否有用需要分情况讨论
四个任务 计算密集型的 10s
单核情况下
开线程更省资源
多核情况下
开进程 10s
开线程 40s
四个任务 IO密集型的
单核情况下
开线程更节省资源
多核情况下
开线程更节省资
2 死锁:
from threading import Thread,Lock,current_thread,RLock
import time
# RLock 递归锁
# Rlock可以被第一个抢到锁的人连续的acquire和release
#每acquire一次锁身上的计数加1
#每release一次锁身上的计数减1
#只要锁的计数不为0 其他人都不能抢
mutexA = Lock()
mutexB = Lock()
#mutexA = mutexB = RLock() # A B现在是同一把锁
class MyThread(Thread):
def run(self): # 创建线程自动触发run方法 run方法内调用func1 func2相当于也是自动触发
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()
3,信号量 (Semaphore)
# 信号量可能在不同的领域中 对应不同的知识点
互斥锁:一个厕所(一个坑位)
信号量:公共厕所(多个坑位)
from threading import Semaphore,Thread
import time
import random
# 同时有四十个线程来抢五个坑位,即有五个线程抢到五个坑位,同时执行五个线程
五个人同时抢到锁,同时释放锁
sm = Semaphore(5) # 造了一个含有五个的坑位的公共厕所
def task(name):
sm.acquire()
print('%s占了一个坑位'%name)
time.sleep(random.randint(1,3)) 抢到锁睡得时间不一样
sm.release()
for i in range(40):
t = Thread(target=task,args=(i,))
t.start()
4,event事件 一个子进程等待另一个子进程接受再走,或者一个子线程等待另一个子线程结束再走
即 子等子时,就用event事件,子执行完毕给另一个子发信号,另一个子只要等待到信号,就开始立即执行
案列: 红灯与车 (灯一个,车多个,即给车多个线程)
from threading import Event,Thread
import time
# 先生成一个event对象********
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=('伞兵%s'%i,))
t.start()
5,队列(多线程优先用队列,而不是加锁)
同一个进程下的多个线程本来就是数据共享 为什么还要用队列
因为队列是管道+锁 使用队列你就不需要自己手动操作锁的问题
因为锁操作的不好极容易产生死锁现象
import queue
q = queue.Queue() # 普通队列,产生一个队列对象
q.put('hahha')
print(q.get())
q = queue.LifoQueue() #后进先出队列,==》堆栈
q.put(1)
q.put(2)
q.put(3)
print(q.get())
q = queue.PriorityQueue() #优先级队列,支持你给你放的数据设置优先级,
取的时候,数字越小 优先级越高***********
q.put((10,'haha'))
q.put((100,'hehehe'))
q.put((0,'xxxx'))
q.put((-10,'yyyy'))
print(q.get())