Python 在多线程应用程序中记录锁获取和释放调用
我正在尝试调试一个使用各种锁的多线程Python应用程序 我的想法不是在整个快照中放置log.debug(…)语句来跟踪锁的获取和释放时间和地点,而是对threading.Lock.acquire()和threading.Lock.release()方法进行修饰,并在调用之前加上如下前缀:Python 在多线程应用程序中记录锁获取和释放调用,python,multithreading,debugging,decorator,locks,Python,Multithreading,Debugging,Decorator,Locks,我正在尝试调试一个使用各种锁的多线程Python应用程序 我的想法不是在整个快照中放置log.debug(…)语句来跟踪锁的获取和释放时间和地点,而是对threading.Lock.acquire()和threading.Lock.release()方法进行修饰,并在调用之前加上如下前缀: log.debug("lock::acquire() [%s.%s.%s]" % (currentThread().getName(), self.__class__
log.debug("lock::acquire() [%s.%s.%s]" %
(currentThread().getName(),
self.__class__.__name__,
sys._getframe().f_code.co_name))
其中,log是一些全局的日志记录对象-为了便于讨论
现在理想情况下,应该在运行时派生日志项中的名称“lock”,这样无论在日志上调用哪个lock对象,这些方法都将输出其名称、修饰的操作、调用操作(获取|释放)的当前线程、类和函数
免责声明:我承认上述代码不足以实现任何此类装饰器。这只是为了给我一个我认为可以实现的体验
有人知道我是否可以修饰标准库方法,而无需修改线程库的原始源代码,即从调用应用程序代码中修改
也许我找错了方向,有更好的方法来达到同样的目的,而不使用装饰师?如果情况确实如此,请提前感谢您的指导
解决方案:(受懒人启发)
下面的代码记录了锁定操作,并给出了调用锁定操作的方法/函数的名称(我也在调整代码,使其能够处理条件及其附加的wait()和notify()方法):
其中,日志实例传递给LogLock。init是使用logging.Formatter定义的,如下所示,以提供调用线程的标识:
# With the following format
log_format = \
logging.Formatter('%(asctime)s %(levelname)s %(threadName)s %(message)s')
我最近遇到了你的问题。我将日志记录器设置为自动记录线程名称,如答案中所示。我发现不可能将Lock子类化,所以我必须将其包装,如下所示:
class LogLock(object):
def __init__(self, name):
self.name = str(name)
self.lock = Lock()
def acquire(self, blocking=True):
log.debug("{0:x} Trying to acquire {1} lock".format(
id(self), self.name))
ret = self.lock.acquire(blocking)
if ret == True:
log.debug("{0:x} Acquired {1} lock".format(
id(self), self.name))
else:
log.debug("{0:x} Non-blocking aquire of {1} lock failed".format(
id(self), self.name))
return ret
def release(self):
log.debug("{0:x} Releasing {1} lock".format(id(self), self.name))
self.lock.release()
def __enter__(self):
self.acquire()
def __exit__(self, exc_type, exc_val, exc_tb):
self.release()
return False # Do not swallow exceptions
我记录了对象的id,以便区分多个具有相同名称的锁,您可能不需要它。如果要监视的代码在您的控制下,则创建锁的后代并让您的代码使用它会更容易。在
\uuuu init\uuuuu
构造函数上基于每个实例应用@decorator时,即使是@decorator也更容易。
class LogLock(object):
def __init__(self, name):
self.name = str(name)
self.lock = Lock()
def acquire(self, blocking=True):
log.debug("{0:x} Trying to acquire {1} lock".format(
id(self), self.name))
ret = self.lock.acquire(blocking)
if ret == True:
log.debug("{0:x} Acquired {1} lock".format(
id(self), self.name))
else:
log.debug("{0:x} Non-blocking aquire of {1} lock failed".format(
id(self), self.name))
return ret
def release(self):
log.debug("{0:x} Releasing {1} lock".format(id(self), self.name))
self.lock.release()
def __enter__(self):
self.acquire()
def __exit__(self, exc_type, exc_val, exc_tb):
self.release()
return False # Do not swallow exceptions