2017-09-14 37 views
1

我想在別人的Python代碼中調試異常,而且我不是Python的專家。代碼試圖刷新和刪除一個標準的Python記錄器的所有處理:logger.removeHandler(logger.handlers [0])如何拋出ValueError:list.remove(x):x不在列表中?

def restart_logging(logger_id): 
    logger = logging.getLogger(logger_id) 
    while logger.handlers: 
     handler = logger.handlers[0] 
     handler.flush() 
     logger.removeHandler(handler) 
    init_logging(logger_id) 

這就提出了一個例外:

File "/usr/lib64/python2.6/logging/__init__.py", line 1208, in removeHandler 
    self.handlers.remove(hdlr) 
ValueError: list.remove(x): x not in list 

我查看了StackOverflow上的其他「×不在列表中」的問題,他們所有適合在這兩個類別:

  • 刪除同一項目多次
  • (做 for x in list: list.remove(x)而不是 while list: list.remove(list[0])通常是因爲)
  • 刪除從未在列表中的項目

我看不出在這裏如何適用。

首先,使用while循環:當仍有處理程序時,取第一個(成功或將會有一個IndexError),刷新它,將其刪除。即使這樣刪除了列表中的多個條目,如果列表中仍然有條目,而不是循環遍歷(可能已刪除)對象的for循環,那麼這是一個while循環測試。

望着logging模塊源,它只調用remove()一次,它甚至檢查處理程序列表調用remove()之前:

def removeHandler(self, hdlr): 
    """ 
    Remove the specified handler from this logger. 
    """ 
    if hdlr in self.handlers: 
     #hdlr.close() 
     hdlr.acquire() 
     try: 
      self.handlers.remove(hdlr) 
     finally: 
      hdlr.release() 

此代碼執行的一部分一個Django Web應用程序。例如,我可以理解它是否是一個Java J2EE應用程序,其中兩個線程可以同時訪問同一個列表,並且沒有鎖定讓「獲取第一個項目並將其移除」一個原子操作,因此兩個線程都會看到相同的元素在列表中,但只有一個會刪除它,另一個會失敗,因爲線程刪除了第一個線程的「是列表中的這個項目」和「從列表中刪除這個項目」之間的元素。

但據我所知,Python沒有併發性,並且使用全局解釋器鎖來一次停止多個事件。所以這是不可能的。

所以,我不明白爲什麼list.remove(x): x not in list這裏發生,我不能做一個測試用例,它可靠地發生。我能做些什麼來進一步瞭解問題?

回答

1

雖然個別操作可能是原子(與如list.remove正如你可能已經注意到操作沿,但這僅由於 CPython的實施細則),removeHandler當然不是。在Python 2.6實現中(你已經非常有幫助地發佈了),上下文切換可以發生在if語句之後和鎖獲取之前(假定hdlr.acquire()的作用是這樣)。所以如果兩個線程同時調用這個函數,當一個線程隨後釋放它對GIL的保留時,它將保證會引發異常,因爲另一個線程貫穿整個事件完成(原始線程將從if內部繼續,處理程序是仍然指向原來的那個,它將獲得IO鎖,然後嘗試從列表中刪除它,導致不需要的異常)。

在Python 2.7,這已得到修復和removeHandler方法改變爲這樣:

def removeHandler(self, hdlr): 
     """ 
     Remove the specified handler from this logger. 
     """ 
     _acquireLock() 
     try: 
      if hdlr in self.handlers: 
       self.handlers.remove(hdlr) 
     finally: 
      _releaseLock() 

注意如何鎖if語句之前,現在是收購。

相關問題