其他锁与队列
# 死锁现象
# 介绍
- B锁在线程1上,A锁在线程2上,他们两个互相等待对方释放锁,于是就出现了死锁现象
- 所以互斥锁应该谨慎的使用,防止出现死锁现象
# 例子
from threading import Thread, Lock
import time
mutexA = Lock()
mutexB = Lock()
class task(Thread):
def run(self):
self.task1()
self.task2()
def task1(self):
mutexA.acquire()
print("{} 抢到了A锁!".format(self.name))
mutexB.acquire()
print("{} 抢到了B锁!".format(self.name))
mutexA.release()
mutexB.release()
def task2(self):
mutexB.acquire()
print("{} 抢到了B锁!".format(self.name))
time.sleep(2)
mutexA.acquire()
print("{} 抢到了A锁!".format(self.name))
mutexA.release()
mutexB.release()
if __name__ == "__main__":
for i in range(2):
t = task()
t.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 递归锁
# 介绍
- 递归锁可以被第一个抢到锁的进程或线程,连续的acquire和release
- 它的内部有一个计数器,每acquire一次计数加一,每release一次计数减一
- 只有当计数重新为0时,它才会被真正释放,此时其他进程或线程才能抢到锁
# 使用方法
# 导入线程递归锁(另外多进程模块也有递归锁)
from threading import Thread, RLock
# 加锁、释放锁的方法和互斥锁一样
# 不同的是,只有锁重新为0,也就是加多少次锁,就释放多少次锁,锁才会被真正的释放
def task():
mutex.acquire()
print("{} 抢到锁,锁+1!".format(current_thread().name))
mutex.acquire()
print("{} 锁+1!".format(current_thread().name))
mutex.release()
print("{} 锁-1!".format(current_thread().name))
mutex.release()
print("{} 锁为0!".format(current_thread().name))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用例子
from threading import Thread, RLock,current_thread
mutex = RLock()
def task():
mutex.acquire()
print("{} 抢到锁,锁+1!".format(current_thread().name))
mutex.acquire()
print("{} 锁+1!".format(current_thread().name))
mutex.release()
print("{} 锁-1!".format(current_thread().name))
mutex.release()
print("{} 锁为0!".format(current_thread().name))
if __name__ == "__main__":
t_list = []
for i in range(3):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 信号量
# 介绍
- 信号量在不同的阶段对应不同的技术点
- 在并发编程中,信号量是锁,可以被多个进程或线程同时抢到的锁,可以指定这把锁能被多少进程或线程同时持有
- 除此之外,其他的和互斥锁一样,也是要释放锁,其他没有锁的线程才能抢锁执行
# 使用方法
# 导入信号量(另外多进程模块也有信号量)
from threading import Thread, Semaphore
# Semaphore(9)是指锁最多同时被9个线程持有
# 第10个如果要执行,就得等待前面拿到锁的线程释放锁,然后抢锁
mutex = Semaphore(9)
def task():
mutex.acquire()
print('{} 抢到锁!'.format(current_thread().name))
mutex.release()
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 使用例子
from threading import Thread, Semaphore, current_thread
import time
mutex = Semaphore(9)
def task():
mutex.acquire()
print('{} 抢到锁!'.format(current_thread().name))
time.sleep(2)
mutex.release()
t_list = []
for i in range(10):
t = Thread(target=task)
t.start()
t_list.append(t)
- 此处由于第10个线程时,锁已经被抢完了,所以要等待2秒前面的线程释放锁,才能抢锁执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 线程的Event事件
# 介绍
- 线程或进程中的event事件,用于控制其他子进程或子线程的执行状态
- 比如线程1用于控制线程2执行,线程2会阻塞等待事件开始
- 当线程1使用set方法时,事件开始,线程2会跳出停止阻塞继续执行
# 使用例子
- from threading import Thread, Event
import time
event = Event()
def task():
print('任务暂停!')
time.sleep(2)
print('任务开始!')
event.set()
def nijia():
print('等待任务开始!')
event.wait()
print('nijia开始执行任务!')
t1 = Thread(target=task)
t2 = Thread(target=nijia)
t1.start()
t2.start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# LifoQueue队列
# 介绍
- 队列是管道 + 锁,虽然线程是数据共享,但使用Queue可以使数据操作更安全
- 除了先进先出的队列,还有后进先出的队列,就是LifoQueue队列(堆栈)
- 就像叠衣服,从下往上叠上去,从上往下取出来
# 使用方法
# 导入模块中的类
from queue import LifoQueue
# 除了后进先出,使用方法和普通队列一样
q = LifoQueue()
q.put(1)
q.put(2)
print(q.get())
print(q.get())
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# PriorityQueue
# 介绍
- PriorityQueue是优先级队列,与普通队列不同的是,在插入数据时,我们需要指定优先级
- put括号内放入一个元组,元组的第一个下标的数值表示优先级,第二个表示要插入的值 (设置的优先级数值越小,优先级越高)
- 在取数据时,无论先后顺序,它都会优先取优先级高的数据
- 如果是同优先级,则是按先进先出的原则
# 使用方法
# 导入模块中的类
from queue import LifoQueue
q = PriorityQueue()
q.put((-1,'111'))
q.put((0,'222'))
q.put((0,'333'))
print(q.get())
print(q.get())
print(q.get())
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9