一.关于GIL与自定义互斥锁的区别
1.GIL是python解释器自带的锁,自定义互斥锁是我们程序里面自定义的锁
2.GIL锁只保证关于垃圾回收那一部分的数据是安全的,但是程序里面自定义的数据GIL无法保证,只能增加自定义锁
代码如下:
1.有自定义互斥锁的情况
from threading import Thread,Lock
import time,random
n=100
mutex=Lock()
def task():
global n
with mutex:
temp=n
time.sleep(0.1)
n=temp-1
if __name__ == '__main__':
l=[]
for i in range(100):
t=Thread(target=task)
l.append(t)
t.start()
for t in l:
t.join()
print(n) #0
2.只有GIL锁,没有自定义互斥锁的情况
from threading import Thread,Lock
import time,random
n=100
# mutex=Lock()
def task():
global n
# with mutex:
temp=n
time.sleep(0.1)
n=temp-1
if __name__ == '__main__':
l=[]
for i in range(100):
t=Thread(target=task)
l.append(t)
t.start()
for t in l:
t.join()
print(n) #99
二.死锁与递归锁
当自定义锁运用的不得当,会造成死锁,死锁的解决方案是递归锁 自定义锁只能aquire一次 而递归锁可以aquire多次
from threading import Thread,Lock,RLock
import time
mutexA=Lock()
mutexB=Lock()
#mutexB=mutexA=RLock()
class Mythead(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print('%s 抢到A锁' %self.name)
mutexB.acquire()
print('%s 抢到B锁' %self.name)
mutexB.release()
mutexA.release()
def f2(self):
mutexB.acquire()
print('%s 抢到了B锁' %self.name)
time.sleep(2)
mutexA.acquire()
print('%s 抢到了A锁' %self.name)
mutexA.release()
mutexB.release()
if __name__ == '__main__':
for i in range(100):
t=Mythead()
t.start()
打印结果:
递归锁可以被一个线程aquire多次,每aquire一次计数加一,导致其它线程无法aquire这把锁(只有计数为零才可以被aquire)
from threading import Thread,Lock,RLock
import time
# mutexA=Lock()
# mutexB=Lock()
mutexB=mutexA=RLock()
class Mythead(Thread):
def run(self):
self.f1()
self.f2()
def f1(self):
mutexA.acquire()
print('%s 抢到A锁' %self.name) ..1 ..2
mutexB.acquire()
print('%s 抢到B锁' %self.name) ..1
mutexB.release()
mutexA.release()
def f2(self):
mutexB.acquire() ..1
print('%s 抢到了B锁' %self.name) ..1
time.sleep(2)
mutexA.acquire()
print('%s 抢到了A锁' %self.name)
mutexA.release()
mutexB.release()
if __name__ == '__main__':
for i in range(100):
t=Mythead()
t.start()
打印结果:
三.信号量
信号量本质也是一把锁,但是与互斥锁不一样的是,信号量是有多把锁,能保证同一时刻多个线程同时运行
四.event事件
多个线程之间需要协同工作,一个线程的运行依赖另一个线程为它做好准备工作
from threading import Thread,Event
import time,random
event=Event()
def light():
print("红灯正亮")
time.sleep(random.randint(1,3))
event.set() #绿灯亮 控制一个信号,
def car(name):
print("%s正在等绿灯" %name)
event.wait() #等绿灯 等待一个信号
print("%s通行" %name)
if __name__ == '__main__':
t1=Thread(target=light)
t1.start()
for i in range(10):
t=Thread(target=car,args=("车辆%s" %i ,))
t.start()
五.线程Queue
import queue
q=queue.Queue() #先进先出
q.put(1)
q.put(2)
q.put(3)
print(q.get()) #1
print(q.get()) #2
print(q.get()) #3
q=queue.LifoQueue() #后进先出
q.put(10)
q.put(20)
q.put(30)
print(q.get()) #30
print(q.get()) #20
print(q.get()) #10
q=queue.PriorityQueue() #元组里面第一个参数越小 优先级越高
q.put((100,"a"))
q.put((0,"b"))
q.put((-1,"c"))
print(q.get()) #c
print(q.get()) #b
print(q.get()) #a