python - 记录多线程应用程序中的锁获取和释放调用

标签 python multithreading debugging decorator locks

我正在尝试调试一个使用各种锁的多线程Python应用程序。

我的想法是装饰方法线程,而不是在整个镜头中放置log.debug(...)语句来跟踪获取和释放锁的位置和时间。 Lock.acquire()threading.Lock.release(),并在它们的调用前面加上如下所示的前缀:

log.debug("lock::acquire() [%s.%s.%s]" %
          (currentThread().getName(),
           self.__class__.__name__,
           sys._getframe().f_code.co_name))

其中 log 是一些全局日志记录对象 - 以便于讨论。

现在,理想情况下,日志条目中的名称“lock”应该在运行时派生,这样无论在日志上调用哪个锁对象,这些方法都将输出其名称、操作修饰,调用操作(获取 | 释放)的当前线程、类和函数。

免责声明:我承认上面给出的代码不足以实现任何此类装饰器。提供它只是为了展示我认为可以实现的目标。

有谁知道我是否可以装饰标准库方法,而不修改线程库的原始源代码,即从我的调用应用程序代码中?

也许我找错了方向,有更好的方法可以在不使用装饰器的情况下达到相同的目的吗?如果确实如此,请提前非常感谢您提供任何指导。

解决方案:(受懒惰者启发)

以下代码记录锁定操作,并为我提供调用锁定操作的方法/函数的名称(我还调整代码以使用条件及其附加等待( )notify() 方法):

# Class to wrap Lock and simplify logging of lock usage
class LogLock(object):
    """
    Wraps a standard Lock, so that attempts to use the
    lock according to its API are logged for debugging purposes

    """
    def __init__(self, name, log):
        self.name = str(name)
        self.log = log
        self.lock = threading.Lock()
        self.log.debug("{0} created {1}".format(
            inspect.stack()[1][3], self.name))

    def acquire(self, blocking=True):
        self.log.debug("{0} trying to acquire {1}".format(
            inspect.stack()[1][3], self.name))
        ret = self.lock.acquire(blocking)
        if ret == True:
            self.log.debug("{0} acquired {1}".format(
                inspect.stack()[1][3], self.name))
        else:
            self.log.debug("{0} non-blocking acquire of {1} lock failed".format(
                inspect.stack()[1][3], self.name))
        return ret

    def release(self):
        self.log.debug("{0} releasing {1}".format(inspect.stack()[1][3], 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

传递给 LogLock.init 的日志实例是使用 logging.Formatter 定义的,如下所示,以便为我提供调用线程的标识:

# With the following format
log_format = \
        logging.Formatter('%(asctime)s %(levelname)s %(threadName)s %(message)s')

最佳答案

我最近遇到了你的问题。我将记录器设置为自动记录线程名称,例如 this回答。我发现不可能子类化 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,以便我可以区分具有相同名称的多个锁,您可能不需要它。

关于python - 记录多线程应用程序中的锁获取和释放调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5327614/

相关文章:

python - 命名管道竞争条件?

Python正则表达式: making multiple different substitutions in a single pass using Groups

multithreading - 这里需要 volatile 吗?

debugging - IntelliJ IDEA 2017 - 缺少调试窗口

python - 在 SymPy 中,为什么两个随机变量相加会产生难以理解的结果?

python - 使用 f 字符串格式化字符串

c# - ReaderWriterLockSlim 与 Monitor

c++ - 多线程程序仅适用于打印语句

Android Debug Tracing问题

objective-c - 为什么 LLDB 使用我的结构的错误字段进行算术运算?