2017-10-19 26 views
1

J'ai un programme exécuté simultanément où je veux créer un journal pour chaque processus enfant. Je vais d'abord décrire ma configuration puis le problème auquel je suis confronté. Voici mes modules principaux:Problèmes avec les modules multithreading/logging de 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: ce module fait une gestion des exceptions et je ne sais pas pourquoi il pourrait interférer mais je suppose que je l'inclurais juste au cas où.

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 

Maintenant, sur mon issue. Je recevais l'erreur décrite dans cet article: https://github.com/opencv/opencv/issues/5150. Par conséquent, j'ai écrit la ligne mp.set_start_method('spawn') dans mp_handler().

Après le débogage, cependant, je trouve que cette ligne était à l'origine de la ligne logger = logging.getLogger(logger_id)mp_worker() pour créer un enregistreur NOUVEAU par opposition à obtenir celui créé dans le parent, à savoir mp_handler(). J'ai été capable de voir cela en imprimant hex(id(logger)) à la fois dans les modules parent et enfant et de voir que les emplacements en mémoire sont différents. En effet, comme je l'ai dit, écrire mp.set_start_method('fork') évite ce problème (cela me semble très approximatif, car je crois comprendre que spawn créera un nouvel espace pour l'enregistreur). Problème principal: Donc, le problème est, comment puis-je contourner le fait que j'ai besoin que la méthode start soit définie sur 'spawn' pour le plaisir d'OpenCV, mais que je doive l'éteindre pour que la communication du journal entre modules (c'est-à-dire pour que mp_worker reconnaisse son logger_id correct afin de se connecter au bon fichier)? Dans le cadre d'une bonne pratique, je veux garder toutes les configs de journalisation hors des enfants et des sous-modules.

problème secondaire: supposer que j'ignore le fait que j'ai besoin d'OpenCV et que je mets la méthode à "fork". Dans ce cas, j'ai remarqué qu'aucune des instructions logging.info() dans la fonction function_with_open_cv() n'atteint jamais le journal! Donc, en supposant que votre recommandation implique de le mettre à la fourchette, quel est le travail ici? EDIT: FIXE! Ceci est également causé par OpenCV. Le problème persiste donc ... comment utiliser un processus de spawn et ne pas perdre mon identifiant de logger?

Merci beaucoup!

Répondre

-1

Vous ne devez pas configurer la journalisation avant qu'un processus ne soit généré, mais après. Voir the documentation pour un exemple de la façon de le faire correctement. Cela s'applique à Python 3, mais si vous avez besoin de l'exécuter sous Python 2, vous pouvez utiliser le logutils package, qui fournit les classes QueueListener et QueueHandler.

Le livre de recettes de journalisation contient d'autres exemples de code relatifs à l'utilisation de la journalisation avec multiprocessing.

+0

Ce serait une bien meilleure réponse si vous êtes allé dans certains détails sur ce qui ne va pas ici. –

+0

@SamHartman ce n'est pas une raison pour downvote. Il n'est pas vraiment possible d'expliquer le threading, le forking et leurs interactions d'une manière raisonnablement concise. –

+0

J'ai downvoted parce que je pensais que vous n'aviez pas répondu à la question: je pensais en particulier qu'une partie de la question demandait ce qui se passait. En lisant cependant, je me rends compte que l'OP a seulement demandé comment réparer. Dans une application suffisamment complexe, je ne pense pas que ce soit une bonne réponse, mais je regrette le downvote. Absent un edit, il ne me laissera pas changer. –