本文講python中的四種鎖
Lock互斥鎖
使用前
num = 0
def a():
global num
for _ in range(10000000):
num += 1
def b():
global num
for _ in range(10000000):
num += 1
if __name__ == `__main__`:
t1=Thread(target=a)
t1.start()
t2=Thread(target=b)
t2.start()
t1.join()
t2.join()
print(num) #基本永遠會小於20000000
使用後
num = 0
def a(lock):
global num
for _ in range(1000000):
with lock:
num += 1
def b(lock):
global num
for _ in range(1000000):
with lock:
num += 1
if __name__ == `__main__`:
lock = threading.Lock()
t1=Thread(target=a, args=(lock,))
t1.start()
t2=Thread(target=b, args=(lock,))
t2.start()
t1.join()
t2.join()
print(num) #永遠會輸出20000000
RLock重用鎖
#在之前的程式碼中永遠不可能出現鎖在沒釋放之前重新獲得鎖,但rlock可以做到,但只能發生在一個執行緒中,如:
num = 0
def a(lock):
with lock:
print("我是A")
b(lock)
def b(lock):
with lock:
print("我是b")
if __name__ == `__main__`:
lock = threading.Lock()
t1 = Thread(target=a, args=(lock,))
t1.start() #會發生死鎖,因為在第一次還沒釋放鎖後,b就準備上鎖,並阻止a釋放鎖
使用後
if __name__ == `__main__`:
lock = threading.RLock() #只需要改變鎖為RLock程式馬上恢復
t1 = Thread(target=a, args=(lock,))
t1.start()
Condition同步鎖
#這個程式我們模擬甲乙對話
Jlist = ["在嗎", "幹啥呢", "去玩兒不", "好吧"]
Ylist = ["在呀", "玩兒手機", "不去"]
def J(list):
for i in list:
print(i)
time.sleep(0.1)
def Y(list):
for i in list:
print(i)
time.sleep(0.1)
if __name__ == `__main__`:
t1 = Thread(target=J, args=(Jlist,))
t1.start()
t1.join()
t2 = Thread(target=Y, args=(Ylist,))
t2.start()
t2.join() #上面的程式輸出後發現效果就是我們們想要的,但是我們每次輸出後都要等待0.1秒,也無法正好確定可以拿到時間片的最短時間值,並且不能保證每次正好都是另一個執行緒執行。因此,我們用以下方式,完美解決這些問題。
使用後
Jlist = ["在嗎", "幹啥呢", "去玩兒不", "好吧"]
Ylist = ["在呀", "玩兒手機", "不去","哦"]
def J(cond, list):
for i in list:
with cond:
print(i)
cond.notify()
cond.wait()
def Y(cond, list):
for i in list:
with cond:
cond.wait()
print(i)
cond.notify()
if __name__ == `__main__`:
cond = threading.Condition()
t1 = Thread(target=J, args=(cond, Jlist))
t2 = Thread(target=Y, args=(cond, Ylist))
t2.start()
t1.start() #一定保證t1啟動在t2之後,因為notify傳送的訊號要被t2接受到,如果t1先啟動,會發生阻塞。
Seamplore訊號量
使用前
class B(threading.Thread):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
time.sleep(1)
print(self.name)
class A(threading.Thread):
def __init__(self):
super().__init__()
def run(self):
for i in range(100):
b = B(i)
b.start()
if __name__ == `__main__`:
a = A()
a.start() #執行後發現不斷在輸出
使用後
class B(threading.Thread):
def __init__(self, name, sem):
super().__init__()
self.name = name
self.sem = sem
def run(self):
time.sleep(1)
print(self.name)
sem.release()
class A(threading.Thread):
def __init__(self, sem):
super().__init__()
self.sem = sem
def run(self):
for i in range(100):
self.sem.acquire()
b = B(i, self.sem)
b.start()
if __name__ == `__main__`:
sem = threading.Semaphore(value=3)
a = A(sem)
a.start() #通過執行上面的程式碼,我們發現一次只能輸出三個數字,sem控制訪問併發量