python threading模塊的Lock和RLock區別


首先了解這兩者是什么。

以下說明參考自python官網

Lock:Lock被稱為原始鎖,原始鎖是一個在鎖定時不屬於特定線程的同步基元組件,它是能用的最低級的同步基元組件。原始鎖處於 "鎖定" 或者 "非鎖定" 兩種狀態之一。它被創建時為非鎖定狀態。它有兩個基本方法, acquire() 和 release() 。當狀態為非鎖定時, acquire() 將狀態改為鎖定並立即返回。當狀態是鎖定時, acquire() 將阻塞至其他線程調用 release() 將其改為非鎖定狀態,然后 acquire() 調用重置其為鎖定狀態並返回。 release() 只在鎖定狀態下調用; 它將狀態改為非鎖定並立即返回。如果嘗試釋放一個非鎖定的鎖,則會引發 RuntimeError  異常。鎖支持 上下文管理協議,即支持with語句,下文例子中會用到。

RLock:RLock被稱為重入鎖,若要鎖定鎖,線程調用其 acquire() 方法;一旦線程擁有了鎖,方法將返回。若要解鎖,線程調用 release() 方法。 acquire()/release() 對可以嵌套,重入鎖必須由獲取它的線程釋放。一旦線程獲得了重入鎖,同一個線程再次獲取它將不阻塞。只有最終 release() (最外面一對的 release() ) 將鎖解開,才能讓其他線程繼續處理 acquire() 阻塞。;線程必須在每次獲取它時釋放一次。

兩者使用的方法大部分還是相同的,下面根據以上紅色強調部分描述一下二者的區別

①是名稱的區別,一個叫原始鎖,一個叫重入鎖,這沒啥好說的

②Lock在鎖定時不屬於特定線程,也就是說,Lock可以在一個線程中上鎖,在另一個線程中解鎖。而對於RLock來說,只有當前線程才能釋放本線程上的鎖,即解鈴還須系鈴人:

 

import threading
import time

lock = threading.Lock()
lock.acquire()

def func():
    lock.release()
    print("lock is released")

t = threading.Thread(target=func)
t.start()

輸出結果為:lock is released

 

上面代碼中,在主線程中創建鎖,並上鎖,但是是在t線程中釋放鎖,結果正常輸出,說明一個線程上的鎖,可以由另外線程解鎖。如果把上面的鎖改為RLock則報錯

③也是這兩者最大的區別了,RLock允許在同一線程中被多次acquire。而Lock卻不允許這種情況。也就是說,下面的情況對於RLock是允許的:

import threading

rlock = threading.RLock()

def func():
    if rlock.acquire():   # 第一把鎖
        print("first lock")
        if rlock.acquire():  # 第一把鎖沒解開的情況下接着上第二把鎖
            print("second lock")
            rlock.release()  # 解開第二把鎖
        rlock.release()  # 解開第一把鎖


t = threading.Thread(target=func)
t.start()

輸出結果:

   first lock
   second lock

注意上面強調的同一線程中,因為對於RLock來說只有當前線程才能釋放本線程上的鎖,並不能在t1線程中已經執行rlock.acquire,且未釋放鎖的情況下,在另一個t2線程中還能執行rlock.acquire(這種情況會導致t2阻塞)

那么,既然一個線程可以通過Lock來獲得一把鎖,干嘛還要使用RLock去鎖上加鎖?考慮一下這種情況:

import threading
import time

lock1 = threading.RLock()

def inner():
    with lock1:
        print("inner1 function:%s" % threading.current_thread())

def outer():
    print("outer function:%s" % threading.current_thread())
    with lock1:
        inner()

if __name__ == "__main__":
    t1 = threading.Thread(target=outer)
    t2 = threading.Thread(target=outer)
    t1.start()
    t2.start()
結果:

  outer function:<Thread(Thread-1, started 12892)>
  inner1 function:<Thread(Thread-1, started 12892)>
  outer function:<Thread(Thread-2, started 7456)>
  inner1 function:<Thread(Thread-2, started 7456)>

首先只看t1線程,當執行到outer函數時,首先打印outer function:<Thread(Thread-1, started 12892)>,然后用lock1給當前線程上了一把鎖,然后執行inner函數,在inner里面又需要用lock1來上一把鎖,如果此時用Lock的話,由於已經上了一把鎖,程序會因為第二次無法獲得鎖而導致t1阻塞,程序阻塞之后又沒法釋放鎖,所以會導致程序死鎖。這種情況下,RLock就派上用場了。t2線程執行過程和t1一樣,這里只是多加個線程看起來酷炫一些

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM