记录多进程/多线程python脚本时出现死锁

记录多进程/多线程python脚本时出现死锁,python,multithreading,logging,multiprocess,Python,Multithreading,Logging,Multiprocess,我面临从以下脚本收集日志的问题。 一旦我将SLEEP\u TIME设置为太“小”的值,LoggingThread 线程以某种方式阻止日志模块。脚本在记录请求时冻结 在操作功能中。如果SLEEP\u TIME约为0.1,脚本将收集 所有日志消息如我所料 我试着跟随,但这并不能解决我的问题 import multiprocessing import threading import logging import time SLEEP_TIME = 0.000001 logger = loggin

我面临从以下脚本收集日志的问题。 一旦我将
SLEEP\u TIME
设置为太“小”的值,LoggingThread 线程以某种方式阻止日志模块。脚本在记录请求时冻结 在
操作
功能中。如果
SLEEP\u TIME
约为0.1,脚本将收集 所有日志消息如我所料

我试着跟随,但这并不能解决我的问题

import multiprocessing
import threading
import logging
import time

SLEEP_TIME = 0.000001

logger = logging.getLogger()

ch = logging.StreamHandler()
ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(): %(message)s'))
ch.setLevel(logging.DEBUG)

logger.setLevel(logging.DEBUG)
logger.addHandler(ch)


class LoggingThread(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while True:
            logger.debug('LoggingThread: {}'.format(self))
            time.sleep(SLEEP_TIME)


def action(i):
    logger.debug('action: {}'.format(i))


def do_parallel_job():

    processes = multiprocessing.cpu_count()
    pool = multiprocessing.Pool(processes=processes)
    for i in range(20):
        pool.apply_async(action, args=(i,))
    pool.close()
    pool.join()



if __name__ == '__main__':

    logger.debug('START')

    #
    # multithread part
    #
    for _ in range(10):
        lt = LoggingThread()
        lt.setDaemon(True)
        lt.start()

    #
    # multiprocess part
    #
    do_parallel_job()

    logger.debug('FINISH')
如何在多进程和多线程脚本中使用日志模块?

这可能是

这个问题在任何有锁、线程和叉的情况下都很常见。如果线程1有一个锁,而线程2调用fork,那么在fork进程中,只有线程2,锁将永远保持。在您的例子中,这就是
logging.StreamHandler.lock


可以找到
日志记录
模块的修复程序()。请注意,您还需要处理任何其他锁。

我最近在使用日志模块和Paths多处理库时遇到了类似的问题。仍然不是100%确定,但在我的例子中,问题可能是因为日志处理程序试图从不同的进程中重用锁对象

能够使用默认日志处理程序的简单包装来修复它:

import threading
from collections import defaultdict
from multiprocessing import current_process

import colorlog


class ProcessSafeHandler(colorlog.StreamHandler):
    def __init__(self):
        super().__init__()

        self._locks = defaultdict(lambda: threading.RLock())

    def acquire(self):
        current_process_id = current_process().pid
        self._locks[current_process_id].acquire()

    def release(self):
        current_process_id = current_process().pid
        self._locks[current_process_id].release()

我似乎无法重现你的问题。您能提供线程创建/启动代码吗?请确保:action()的执行将冻结(永远不会生成带有“actions:”的日志消息)。日志线程永远都在工作。死锁的概率取决于
SLEEP\u TIME
值。