怎么在Python項目中實現(xiàn)一個讀寫鎖-創(chuàng)新互聯(lián)

這篇文章給大家介紹怎么在Python項目中實現(xiàn)一個讀寫鎖,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

成都創(chuàng)新互聯(lián)成立以來不斷整合自身及行業(yè)資源、不斷突破觀念以使企業(yè)策略得到完善和成熟,建立了一套“以技術(shù)為基點,以客戶需求中心、市場為導(dǎo)向”的快速反應(yīng)體系。對公司的主營項目,如中高端企業(yè)網(wǎng)站企劃 / 設(shè)計、行業(yè) / 企業(yè)門戶設(shè)計推廣、行業(yè)門戶平臺運營、成都app開發(fā)、移動網(wǎng)站建設(shè)、微信網(wǎng)站制作、軟件開發(fā)、眉山服務(wù)器托管等實行標(biāo)準(zhǔn)化操作,讓客戶可以直觀的預(yù)知到從成都創(chuàng)新互聯(lián)可以獲得的服務(wù)效果。

簡單的實現(xiàn)


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()

這是讀寫鎖的一個簡單的實現(xiàn),self.read_num 用來保存獲得讀鎖的線程數(shù),這個屬性屬于臨界區(qū),對其操作也要加鎖,所以這里需要一個保護內(nèi)部數(shù)據(jù)的額外的鎖 self._extra 。

但是這個鎖是不公平的。理想情況下,線程獲得所的機會應(yīng)該是一樣的,不管線程是讀操作還是寫操作。而從上述代碼可以看到,讀請求都會立即設(shè)置 self.read_num += 1,不管有沒有獲得鎖,而寫請求想要獲得鎖還得等待 read_num 為 0 。

所以這個就造成了只有鎖沒有被占用或者沒有讀請求時,可以獲得寫權(quán)限。我們應(yīng)該想辦法避免讀模式鎖長期占用。

讀寫鎖的優(yōu)先級


讀寫鎖也有分 讀優(yōu)先 和 寫優(yōu)先。上面的代碼就屬于讀優(yōu)先。

如果要改成寫優(yōu)先,那就換成去記錄寫線程的引用計數(shù),讀和寫在同時競爭時,可以讓寫線程增加寫的計數(shù),這樣可使讀線程的讀鎖一直獲取不到, 因為讀線程要先判斷寫的引用計數(shù),若不為0,則等待其為 0,然后進行讀。這部分代碼不羅列了。

但這樣顯然不夠靈活。我們不需要兩個相似的讀寫鎖類。我們希望重構(gòu)我們代碼,使它更強大。

改進


為了能夠滿足自定義優(yōu)先級的讀寫鎖,要記錄等待的讀寫線程數(shù),并且需要兩個條件 threading.Condition 用來處理哪方優(yōu)先的通知。計數(shù)引用可以擴大語義:正數(shù):表示正在讀操作的線程數(shù),負數(shù):表示正在寫操作的線程數(shù)(最多-1)

在獲取讀操作時,先然后判斷時候有等待的寫線程,沒有,進行讀操作,有,則等待讀的計數(shù)加 1 后等待 Condition 通知;等待讀的計數(shù)減 1,計數(shù)引用加 1,繼續(xù)讀操作,若條件不成立,循環(huán)等待;

在獲取寫操作時,若鎖沒有被占用,引用計數(shù)減 1,若被占用,等待寫線程數(shù)加 1,等待寫條件 Condition 的通知。

讀模式和寫模式的釋放都是一樣,需要根據(jù)判斷去通知對應(yīng)的 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  # 等待獲取讀鎖的線程數(shù)
    self.write_waiter = 0  # 等待獲取寫鎖的線程數(shù)
    self.state = 0     # 正數(shù):表示正在讀操作的線程數(shù)  負數(shù):表示正在寫操作的線程數(shù)(最多-1)
    self.owners = []    # 正在操作的線程id集合
    self.write_first = True # 默認寫優(yōu)先,F(xiàn)alse表示讀優(yōu)先

  def write_acquire(self, blocking=True):
    # 獲取寫鎖只有當(dāng)
    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):
    # 獲取寫鎖只有當(dāng)鎖沒人占用,或者當(dāng)前線程已經(jīng)占用
    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:  # 如果有寫操作在等待(默認寫優(yōu)先)
          self.wcond.notify()
        elif self.read_waiter:
          self.rcond.notify_all()
        elif self.write_waiter:
          self.wcond.notify()

  read_release = unlock
  write_release = unlock

關(guān)于怎么在Python項目中實現(xiàn)一個讀寫鎖就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

網(wǎng)站題目:怎么在Python項目中實現(xiàn)一個讀寫鎖-創(chuàng)新互聯(lián)
網(wǎng)頁鏈接:http://bm7419.com/article36/ggcpg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站制作、標(biāo)簽優(yōu)化移動網(wǎng)站建設(shè)關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司