2017-09-14 83 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语句之前,现在是收购。

相关问题