2017-10-19 171 views
1

我有一个并发运行的程序,我想为每个子进程创建一个日志。我将首先描述我的设置,然后描述我面临的问题。这里是我的主要模块:Python的多线程/日志记录模块的问题

mp_handler.py:

import logging 
import multiprocessing as mp 

def mp_handler(target, args_list): 

    # configure logs 
    for args in args_list: 
     logger_id = args[0] # first arg suffices to id a process, in my case 
     logger = logging.getLogger(logger_id) 
     handler = logging.FileHandler(logger_id + '.log') 
     logger.setLevel(logging.INFO) 
     logger.addHandler(handler) 

    mp.set_start_method('spawn') # bug fix, see below   

    # build each process 
    for args in args_list: 
     p = mp.Process(target = target, args = args) 
     p.start() 

mp_worker.py:

import logging 
from deco_module import deco 
from my_module import function_with_open_cv 

@deco 
def mp_worker(args): 
    logger_id = arg[0] 
    logger = logging.getLogger(logger_id) 

    log.info("Information about process %s" % log_id)   

    # do a lot of stuff with openCV3 
    function_with_open_cv(args)  # also logs to this child's log file 

deco_module.py:这个模块做了一些异常处理和我不知道为什么它可能干扰,但我想我会包括它以防万一。

from functools import wraps 
import logging 

def deco(function): 

    @wraps(function) 
    def wrapper(*args): 
     logger_id = *args[0] 
     logger = logging.getLogger(logger_id) 
     try: 
      function(*args) 
     except: 
      logger.info('a message in case the child fails.') 

    return wrapper 

现在,就我的问题。我遇到了这篇文章中描述的错误:https://github.com/opencv/opencv/issues/5150。因此,我写了mp.set_start_method('spawn')mp_handler()

但是,在调试之后,我发现该行导致logger = logging.getLogger(logger_id)mp_worker()创建了一个NEW记录器,而不是获取父记录中创建的记录器,即mp_handler()。通过在父模块和子模块中都打印hex(id(logger)),我可以看到这一点,并且看到内存中的位置不同。事实上,正如我所说,写mp.set_start_method('fork')避免了这个问题(这对我来说非常粗糙,因为我的理解是产卵会为记录器创造一个新的空间)。

主要问题:所以,问题是,我如何解决这个事实,即我需要将启动方法设置为'spawn',以便OpenCV使用,但需要关闭它才能进行日志通信模块(即为了使mp_worker识别其正确的logger_id以便登录到正确的文件)?作为良好实践的一部分,我希望将所有日志配置保留在子模块和子模块之外。

第二个问题:假设我忽略了我需要OpenCV并将该方法设置为'fork'的事实。在这种情况下,我注意到function_with_open_cv()函数中的logging.info()语句都不会进入日志!所以,假设你的建议确实涉及将它设置为fork,那么这里的工作是什么?编辑:固定!这也是由OpenCV造成的。所以问题仍然存在......我如何使用spawn进程而不会丢失我的记录器ID?

非常感谢!

回答

-1

在生成过程之前,不应配置日志记录,但之后。有关如何正确执行此操作的示例,请参见the documentation。这适用于Python 3,但如果您需要在Python 2下运行它,则可以使用logutils package,它提供了QueueListenerQueueHandler类。

日志记录本包含更多与使用multiprocessing日志相关的示例代码。

+0

这将是一个更好的答案,如果你进入一些细节到这里出了什么问题。 –

+0

@SamHartman没有理由downvote。以合理简洁的方式解释线程,分叉和交互是不太可能的。 –

+0

我低估了,因为我认为你没有回答这个问题:特别是我认为问题的一部分问到发生了什么。虽然阅读,我意识到OP只问如何解决。在一个非常复杂的应用程序中,我不认为这是一个好的答案,但我对遗憾的结果感到后悔。没有编辑,它不会让我改变。 –