Python 学习笔记-21

Python 学习笔记-21:

  1. 同步锁
  2. 死锁和递归锁

1. 同步锁

在多线程执行代码的过程中可能会由于CPU过早的切换线程导致某一线程内代码未完全执行,因此我们需要对该段代码加锁。以确定CPU在执行完此段代码之后再执行切换线程

未加锁代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import threading
import time

num = 100

def addNum():
global num
temp = num
time.sleep(0.1) # 起阻隔作用
num = temp - 1

thread_list = []

for i in range(100)
t = threading.Thread(target=addNum())
t.start()
thread_list.append(t)


for t in thread_list:
t.join()

print('final num:', num) # 在视频中由于阻隔的存在导致num输出值小于100,但是我在实践的过程中发现并没有用

加锁后代码示例:

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
28
import threading
import time

num = 100
r = threading.Lock() # 创建一个锁

def addNum():
global num
r.acquire() # 打开锁
temp = num
time.sleep(0.1)
num = temp - 1
r.release() 关闭锁


thread_list = []

for i in range(100):

t = threading.Thread(target=addNum())
t.start()
thread_list.append(t)


for t in thread_list:
t.join()

print('final num:', num) # 加锁之后变成局部串行

加锁的意义:

可以使被锁部分变成串行,如果直接用join则会是多线程变得毫无意义

2. 死锁和递归锁

死锁代码示例:

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
28
29
30
31
32
33
34
35
import threading,time

class myThread(threading.Thread):
def doA(self):
lockA.acquire()
print(self.name,"gotlockA",time.ctime())
time.sleep(3)
lockB.acquire()
print(self.name,"gotlockB",time.ctime())
lockB.release()
lockA.release()

def doB(self):
lockB.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lockA.acquire()
print(self.name,"gotlockA",time.ctime())
lockA.release()
lockB.release()
def run(self):
self.doA()
self.doB()
if __name__=="__main__":

lockA=threading.Lock() # 定义一把锁
lockB=threading.Lock() # 定义第二把锁
threads=[]
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join()#等待线程结束,后面再讲。
# 在执行之后程序会卡在第一线程和第二线程的交界处,造成这种现象的原因是第一线程调用了第一把锁,第二线程调用了第二把锁而两个线程都未释放当前锁却都想要获取对方手中的锁,从而造成死锁现象。

递归锁代码示例

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
28
29
30
31
32
33
34
import threading,time

class myThread(threading.Thread):
def doA(self):
lock.acquire()
print(self.name,"gotlockA",time.ctime())
time.sleep(3)
lock.acquire()
print(self.name,"gotlockB",time.ctime())
lock.release()
lock.release()

def doB(self):
lock.acquire()
print(self.name,"gotlockB",time.ctime())
time.sleep(2)
lock.acquire()
print(self.name,"gotlockA",time.ctime())
lock.release()
lock.release()
def run(self):
self.doA()
self.doB()
if __name__=="__main__":

lock=threading.RLock()
threads=[]
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join()#等待线程结束,后面再讲。
# 递归锁通过threading.Rlock()定义,递归锁内部只定义 一把锁,但是这把锁会自带一个计时器,每当有人调用一把锁计时器便开始增加计时,每当有人消除一把锁计时器便减去其中间隔的时间,计时器时间归零。