线程知识点(锁,信号量,队列,条件)
1线程锁
1.1GIL
1.2线程之间的数据安全问题
例如:多个线程对同一块数据进行操作;
比如赋值运算, 一个线程那到数据还没有返回数据结果时间片轮转,引起数据的不安全;
pop, append 操作是安全的,
队列也是安全的
具体操作
`此处输入代码
from threading import Thread, Lock`
lock.acquire()
'''
对数据的操作
'''
lock.release()
1.3递归锁和死锁现象
死锁
是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
死锁现象
两把锁
异步的
操作的时候 抢到一把锁之后还要再去抢第二把锁
一个线程抢到一把锁
另一个线程抢到了另一把锁
解决办法
解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:
示例代码
import time
def fun(lock):
lock.acquire()
print('我还活着')
lock.release()
time.sleep(1)
lock.acquire()
print('你还没死')
lock.release()
def func(lock):
lock.acquire()
lock.acquire()
print('没死')
lock.release()
lock.release()
if __name__ == '__main__':
lock = Lock()
# for i in range(10):
t1 = Thread(target=fun, args=(lock,))
t1.start()
t2 = Thread(target=func, args=(lock,))
t2.start()
递归锁
在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生生死锁
具体代码
from threading import Thread, RLock
fork_lock = noodle_lock = RLock()# 一把锁
def fun1(*args):
noodle_lock.acquire()
#具体操作
fork_lock.acquire()
# 具体操作
fork_lock.release()
noodle_lock.release() #只有当锁释放后才能执行其他操作
递归锁可以解决互斥锁的死锁问题
# 互斥锁
¦ # 两把锁
¦ # 多个线程抢
# 递归锁
¦ # 一把锁
¦ # 多个线程抢
递归锁能够快速的解决死锁问题
# 递归锁好不好?
不好, 出现死锁,肯定是程序的逻辑有问题, 在快速解决死锁的情况下, 修改程序的逻辑。
递归锁
迅速恢复服务 递归锁替换互斥锁
在接下来的时间中慢慢把递归锁替换成互斥锁
能够完善代码的逻辑
提高代码的效率
多个线程之间,用完一个资源再用另外一个资源
先释放一个资源,再去获取一个资源的锁
信号量
与进程的的信号量用法一样
事件Event
wait() 等待 事件内的信号编程True
set() 把信号变成True
clear 把信号变成False
is_set 查看信号状态是否为True
示例代码
from threading import
import time
def fun1(e):
e.wait() #在set没有调用之前下面的语句不执行
print('你好呀,我来了')
def fun2(e):
time.sleep(5)
e.set()
if __name__ == '__mai
e = Event()
t1 = Thread(targe
t1.start()
t2 = Thread(targe
t2.start()
条件 Condition
Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。不断的重复这一过程,从而解决复杂的同步问题
from threading import Condition, Thread
def fun(con, name):
print('欢迎光临')
con.acquire()
con.wait() #使用前后都需要加锁
print('%s go to school'%name)
con.release()
if __name__ == '__main__':
con = Condition()
for i in range(10):
t = Thread(target=fun, args=(con, i))
t.start()
con.acquire()
# con.notify(4) #使用前后都需要加锁 每次默认一个,参数代表通过的次数
# con.notify_all()
con.notifyAll()
con.release()
定时器 Timer
定时器,指定n秒后执行某个操作
from threading import Thread, Timer
def func():
print('Timer: going to ')
if __name__ == '__main__':
t = Timer(5, func)
t.start()
线程队列 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
线程队列 LifoQueue
和栈类似先进后出
from queue import LifoQueue
q = LifoQueue()
q.put(1)
q.put(2)
q.put(3)
print(q.get()) #3
print(q.get()) #2
print(q.get()) #1
PriorityQueue
存储数据时可设置优先级的队列
from queue import PriorityQueue
q = PriorityQueue()
q.put((3,'lei'))
q.put((2,'wen'))
q.put((1,'xuan'))
print(q.get())
print(q.get())
print(q.get())