在 python 中多執行緒中為了防止資源競爭而出現問題,提供了鎖的機制,當乙個執行緒操作資源時進行加鎖,操作完畢後釋放鎖,這樣其他執行緒就不會同時操作資源匯出出現異常。
在 python 多執行緒中注意是兩種鎖:互斥鎖和遞迴鎖
那麼它們有什麼區別呢?
互斥鎖:
一旦乙個執行緒獲得乙個互斥鎖,會阻塞隨後嘗試獲得鎖的執行緒,直到它被釋放;任何執行緒都可以釋放它。
遞迴鎖:
遞迴鎖必須由獲取它的執行緒釋放。一旦執行緒獲得了遞迴鎖,同乙個執行緒再次獲取它將不阻塞;執行緒必須在每次獲取它時釋放一次。
雖然鎖可以防止程式出問題,但是使用鎖不得當是很容易出現死鎖。
死鎖 : 當執行緒a持有獨佔鎖a,並嘗試去獲取獨佔鎖b的同時,執行緒b持有獨佔鎖b,並嘗試獲取獨佔鎖a的情況下,就會發生ab兩個執行緒由於互相持有對方需要的鎖,而發生的阻塞現象,我們稱為死鎖。通俗的將就是一種相互等待無法結束的現象。
下面就演示一下在 python 中可能出現的死鎖
1、互斥鎖使用過程中在子函式內再次加鎖,導致死鎖。
import threading
import time
num =
0# 注意:在普通的互斥鎖中,在同乙個執行緒內如果存在乙個函式多次獲得鎖,就會出現死鎖。注意:遞迴鎖就不會。
llock = threading.lock(
)# 建立乙個互斥鎖
defadd_num
(lock)
:global num
lock.acquire(
) num +=
1 lock.release(
)def
run1
(n, lock)
:global num
print
('task '
,n) time.sleep(1)
lock.acquire(
)for i in
range
(1000000):
# lock.acquire()
add_num(lock)
# lock.release()
lock.release(
)print
(num)
defrun2
(n, lock)
:global num
print
('task '
,n) time.sleep(1)
lock.acquire(
)for i in
range
(1000000):
# lock.acquire()
add_num(lock)
# lock.release()
lock.release(
)print
(num)
if __name__ ==
'__main__'
: start_time = time.time(
)# 定義多執行緒 如果我們傳入的是互斥鎖,那麼就會出現死鎖,
t1 = threading.thread(target=run1, args=
('執行緒a'
, llock)
) t2 = threading.thread(target=run2, args=
('執行緒b'
, llock)
)# 啟動多執行緒
t1.start(
) t2.start(
)# 設定主線程等待子執行緒完成後退出,設定完後主執行緒會阻塞在這裡
t1.join(
) t2.join(
)print
(, time.time(
)- start_time)
2、無論使用遞迴鎖還是互斥鎖,當出現互相等待時,導致死鎖。import threading
import time
'''互相等待的死鎖:
當鎖出現互相等待的時候就會出現死鎖。例如方法1 先將a加鎖,並且想獲取b的鎖,然而此時方法2先將b加鎖,再將b加鎖。由於方法1沒有得到b的鎖因此不會釋放。導致方法2無法獲取b的鎖。出現死鎖。
run1(a, b)
acquire(a) 將a加鎖
acquire(b) 將b加鎖
run2(, b)
acquire(b) 將b加鎖,前提是其他方法先釋放b的鎖
acquire(a)
'''a =
0b =
0# 建立乙個互斥鎖,就算使用遞迴鎖,這種相互等待的也會出現死鎖
locka = threading.lock(
)lockb = threading.lock(
)def
run1
(n):
global a
global b
print
('task '
,n) locka.acquire(
) a +=
1 time.sleep(1)
lockb.acquire(
) b +=
1 lockb.release(
) locka.release(
)print
(a)def
run2
(n):
global a
global b
print
('task '
,n) lockb.acquire(
) b +=
1 locka.acquire(
) a +=
1 locka.release(
) lockb.release(
)print
(a)if __name__ ==
'__main__'
: start_time = time.time(
)# 定義多執行緒
t1 = threading.thread(target=run1, args=
('執行緒a',)
) t2 = threading.thread(target=run2, args=
('執行緒b',)
)# 啟動多執行緒
t1.start(
) t2.start(
)# 設定主線程等待子執行緒完成後退出,設定完後主執行緒會阻塞在這裡
t1.join(
) t2.join(
)print
(, time.time(
)- start_time)
3、通過**來看互斥鎖和遞迴鎖的區別import threading
import time
num =
0# 建立乙個遞迴鎖 在同乙個執行緒裡面可以連續呼叫多次acquire()獲得鎖,但是要保證呼叫acquire的次數和release的次數保持一致。
# 注意:在普通的互斥鎖中,在同乙個執行緒內如果存在乙個函式多次獲得鎖,就會出現死鎖。遞迴鎖就不會。下面具體例子說明
rlock = threading.rlock(
)# 建立乙個遞迴鎖
llock = threading.lock(
)# 建立乙個互斥鎖
defadd_num
(lock)
:global num
lock.acquire(
) num +=
1 lock.release(
)def
run1
(n, lock)
:global num
print
('task '
,n) time.sleep(1)
lock.acquire(
)for i in
range
(1000000):
# lock.acquire()
add_num(lock)
# lock.release()
lock.release(
)print
(num)
defrun2
(n, lock)
:global num
print
('task '
,n) time.sleep(1)
lock.acquire(
)for i in
range
(1000000):
# lock.acquire()
add_num(lock)
# lock.release()
lock.release(
)print
(num)
if __name__ ==
'__main__'
: start_time = time.time(
)# 定義多執行緒 如果我們傳入的是互斥鎖,那麼就會出現死鎖,
# t1 = threading.thread(target=run1, args=('執行緒a', llock))
# t2 = threading.thread(target=run2, args=('執行緒b', llock))
# 傳入遞迴鎖
t1 = threading.thread(target=run1, args=
('執行緒a'
, rlock)
) t2 = threading.thread(target=run2, args=
('執行緒b'
, rlock)
)# 啟動多執行緒
t1.start(
) t2.start(
)# 設定主線程等待子執行緒完成後退出,設定完後主執行緒會阻塞在這裡
t1.join(
) t2.join(
)print
(, time.time(
)- start_time)
python 執行緒死鎖示例
銀行轉賬 兩個賬戶同時給對方轉賬,模擬線程死鎖 from threading import thread,lock from time import sleep 賬戶類 class account def init self,id,balance,lock 每個賬戶自帶乙個鎖,只要數字balance...
Python多執行緒示例
直接使用threading.thread進行多執行緒實現,其中target為要執行的方法或函式,args為引數列表 方法或函式需要的值 結尾加 因為是元組。def pa n for i in range 10 time.sleep 2 print 這是執行緒 str n defpa2 n for i...
Python 多執行緒4 死鎖
encoding utf 8 import threading import time class mythread threading.thread def do1 self global resa,resb if mutexa.acquire msg self.name got resa pri...