前言
本文的文字及圖片來源于網路,僅供學習、交流使用,不具有任何商業用途,如有問題請及時聯系我們以作處理,
以下文章來源于碧茂大資料 ,作者碧茂大資料
讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作,
Python 提供的多執行緒模型中并沒有提供讀寫鎖,讀寫鎖相對于單純的互斥鎖,適用性更高,可以多個執行緒同時占用讀模式的讀寫鎖,但是只能一個執行緒占用寫模式的讀寫鎖,
通俗點說就是當沒有寫鎖時,就可以加讀鎖且任意執行緒可以同時加;而寫鎖只能有一個執行緒,且必須在沒有讀鎖時才能加上,
簡單的實作
import threading
class RWlock(object): def __init__(self):
self._lock = threading.Lock()
self._extra = threading.Lock()
self.read_num = 0
def read_acquire(self):
with self._extra:
self.read_num += 1
if self.read_num == 1:
self._lock.acquire()
def read_release(self):
with self._extra:
self.read_num -= 1
if self.read_num == 0:
self._lock.release()
def write_acquire(self):
self._lock.acquire()
def write_release(self):
self._lock.release()
這是讀寫鎖的一個簡單的實作,self.read_num 用來保存獲得讀鎖的執行緒數,這個屬性屬于臨界區,對其操作也要加鎖,所以這里需要一個保護內部資料的額外的鎖 self._extra ,
但是這個鎖是不公平的,理想情況下,執行緒獲得所的機會應該是一樣的,不管執行緒是讀操作還是寫操作,而從上述代碼可以看到,讀請求都會立即設定 self.read_num += 1,不管有沒有獲得鎖,而寫請求想要獲得鎖還得等待 read_num為 0 ,
所以這個就造成了只有鎖沒有被占用或者沒有讀請求時,可以獲得寫權限,我們應該想辦法避免讀模式鎖長期占用,
讀寫鎖的優先級
讀寫鎖也有分 讀優先 和 寫優先,上面的代碼就屬于讀優先,
如果要改成寫優先,那就換成去記錄寫執行緒的參考計數,讀和寫在同時競爭時,可以讓寫執行緒增加寫的計數,這樣可使讀執行緒的讀鎖一直獲取不到, 因為讀執行緒要先判斷寫的參考計數,若不為0,則等待其為 0,然后進行讀,這部分代碼不羅列了,
但這樣顯然不夠靈活,我們不需要兩個相似的讀寫鎖類,我們希望重構我們代碼,使它更強大,
改進
為了能夠滿足自定義優先級的讀寫鎖,要記錄等待的讀寫執行緒數,并且需要兩個條件threading.Condition 用來處理哪方優先的通知,計數參考可以擴大語意:正數:表示正在讀操作的執行緒數,負數:表示正在寫操作的執行緒數(最多-1)
在獲取讀操作時,先然后判斷時候有等待的寫執行緒,沒有,進行讀操作,有,則等待讀的計數加 1 后等待 Condition 通知;等待讀的計數減 1,計數參考加 1,繼續讀操作,若條件不成立,回圈等待;
在獲取寫操作時,若鎖沒有被占用,參考計數減 1,若被占用,等待寫執行緒數加 1,等待寫條件 Condition 的通知,
讀模式和寫模式的釋放都是一樣,需要根據判斷去通知對應的 Condition:
class RWLock(object): def __init__(self): self.lock = threading.Lock() self.rcond = threading.Condition(self.lock) self.wcond = threading.Condition(self.lock) self.read_waiter = 0 # 等待獲取讀鎖的執行緒數 self.write_waiter = 0 # 等待獲取寫鎖的執行緒數 self.state = 0 # 正數:表示正在讀操作的執行緒數 負數:表示正在寫操作的執行緒數(最多-1) self.owners = [] # 正在操作的執行緒id集合 self.write_first = True # 默認寫優先,False表示讀優先 def write_acquire(self, blocking=True): # 獲取寫鎖只有當 me = threading.get_ident() with self.lock: while not self._write_acquire(me): if not blocking: return False self.write_waiter += 1 self.wcond.wait() self.write_waiter -= 1 return True def _write_acquire(self, me): # 獲取寫鎖只有當鎖沒人占用,或者當前執行緒已經占用 if self.state == 0 or (self.state < 0 and me in self.owners): self.state -= 1 self.owners.append(me) return True if self.state > 0 and me in self.owners: raise RuntimeError('cannot recursively wrlock a rdlocked lock') return False def read_acquire(self, blocking=True): me = threading.get_ident() with self.lock: while not self._read_acquire(me): if not blocking: return False self.read_waiter += 1 self.rcond.wait() self.read_waiter -= 1 return True def _read_acquire(self, me): if self.state < 0: # 如果鎖被寫鎖占用 return False if not self.write_waiter: ok = True else: ok = me in self.owners if ok or not self.write_first: self.state += 1 self.owners.append(me) return True return False def unlock(self): me = threading.get_ident() with self.lock: try: self.owners.remove(me) except ValueError: raise RuntimeError('cannot release un-acquired lock') if self.state > 0: self.state -= 1 else: self.state += 1 if not self.state: if self.write_waiter and self.write_first: # 如果有寫操作在等待(默認寫優先) self.wcond.notify() elif self.read_waiter: self.rcond.notify_all() elif self.write_waiter: self.wcond.notify() read_release = unlock write_release = unlock
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/58113.html
標籤:Python
上一篇:這個程式是什么意思?
