其他锁与队列
# 死锁现象
# 介绍
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
此处由于第10个线程时,锁已经被抢完了,所以要等待2秒前面的线程释放锁,才能抢锁执行。
# 线程的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队列
# 介绍
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