2015-03-12 8 views
5

मान लीजिए कि मैंने मुख्य प्रक्रिया में लॉगिंग हैंडलर को कॉन्फ़िगर किया है। मुख्य प्रक्रिया कुछ बच्चों को जन्म देती है और os.fork() (लिनक्स में) के कारण सभी लॉगर्स और हैंडलर मुख्य प्रक्रिया से विरासत में प्राप्त होते हैं।फोर्क पर आधारित मल्टीप्रोसेसिंग के दौरान मैं अजगर लॉगर्स और हैंडलर की विरासत को कैसे रोक सकता हूं?

import multiprocessing as mp 
import logging 


def do_log(no): 
    # root logger logs Hello World to stderr (StreamHandler) 
    # BUT I DON'T WANT THAT! 
    logging.getLogger().info('Hello world {}'.format(no)) 


def main(): 
    format = '%(processName)-10s %(name)s %(levelname)-8s %(message)s' 

    # This creates a StreamHandler 
    logging.basicConfig(format=format, level=logging.INFO) 

    n_cores = 4 
    pool = mp.Pool(n_cores) 
    # Log to stdout 100 times concurrently 
    pool.map(do_log, range(100)) 
    pool.close() 
    pool.join() 


if __name__ == '__main__': 
    main() 

इस तरह कुछ प्रिंट होगा: 'Hello World' नीचे दिए गए उदाहरण में कंसोल के लिए 100 बार मुद्रित किया जाएगा

ForkPoolWorker-1 root INFO  Hello world 0 
ForkPoolWorker-3 root INFO  Hello world 14 
ForkPoolWorker-3 root INFO  Hello world 15 
ForkPoolWorker-3 root INFO  Hello world 16 
... 

हालांकि, मैं बच्चे प्रक्रिया सभी लॉगिंग विन्यास के वारिस नहीं करना चाहते माता-पिता से तो do_log से ऊपर के उदाहरण में stderr पर कुछ भी प्रिंट नहीं करना चाहिए क्योंकि StreamHandler नहीं होना चाहिए।

मैं मूल अभिभावक प्रक्रिया में उन्हें हटाने या हटाने के बिना लॉगर्स और हैंडलर को विरासत में कैसे रोकूं?


संपादित करें: यह एक अच्छा विचार बस पूल के प्रारंभ में सभी संचालकों को दूर करने के होगा?

def init_logging(): 
    for logger in logging.Logger.manager.loggerDict.values(): 
     if hasattr(logger, 'handlers'): 
      logger.handlers = [] 

और

pool = mp.Pool(n_cores, initializer=init_logging, initargs=()) 
इसके अलावा

, मैं भी सुरक्षित रूप से close() सब (फाइल) प्रारंभ समारोह के दौरान संचालकों कर सकते हैं?

+0

'multiprocessing.Pool' में प्रारंभिक फ़ंक्शन है जिसे बच्चे में बुलाया जाता है लेकिन मुझे नहीं पता कि यह बिना किसी गंदे हैक के सभी लॉगिंग हैंडलर को कैसे बंद कर सकता है। – tdelaney

+0

क्या मैं बस 'logging.shutdown() कह सकता हूं; logging.Logger.manager.loggerDict = {} 'प्रारंभकर्ता में? या क्या मैं बाद में बनाए गए नए हैंडलरों में हस्तक्षेप करूंगा? या हैकी करने के लिए हो? – SmCaterpillar

+0

इसका उपयोग अनुप्रयोग निकास पर किया जाना चाहिए, इसलिए मैं इसे एक अच्छा समाधान होने की उम्मीद नहीं करता। यह किसी भी बफर को भी फ्लश करता है जो एक बुरी चीज होगी (फ़ाइल लॉगर की कल्पना करें)। असल में, मुझे हैरान है कि मैंने खुद को इस समस्या में नहीं फेंक दिया है ... मैं प्रतिक्रियाओं की प्रतीक्षा कर रहा हूं। लॉगिंग में जोड़ने के लिए यह एक अच्छी नई सुविधा हो सकती है। – tdelaney

उत्तर

4

आप इसे रोकने के लिए की जरूरत नहीं है की जाँच करने के लिए कर सकते हैं, तो आप सिर्फ प्रवेश पदानुक्रम पुन: कॉन्फ़िगर करने की जरूरत है।

मुझे लगता है कि आप पूल प्रारंभकर्ता के साथ सही रास्ते पर हैं। लेकिन चीजों को हैक करने की कोशिश करने के बजाय, लॉगिंग पैकेज को जो करने के लिए डिज़ाइन किया गया है उसे करने दें। लॉगिंग पैकेज कार्यकर्ता प्रक्रियाओं में लॉगिंग पदानुक्रम का पुनर्गठन करने दें।

def main(): 

    def configure_logging(): 
     logging_config = { 
      'formatters': { 
       'f': { 
        'format': '%(processName)-10s %(name)s' 
           ' %(levelname)-8s %(message)s', 
       }, 
      }, 
      'handlers': { 
       'h': { 
        'level':'INFO', 
        'class':'logging.StreamHandler', 
        'formatter':'f', 
       }, 
      }, 
      'loggers': { 
       '': { 
        'handlers': ['h'], 
        'level':'INFO', 
        'propagate': True, 
       }, 
      }, 
      'version': 1, 
     } 

     pname = mp.current_process().name 
     if pname != 'MainProcess': 
      logging_config['handlers'] = { 
       'h': { 
        'level':'INFO', 
        'formatter':'f', 
        'class':'logging.FileHandler', 
        'filename': pname + '.log', 
       }, 
      } 

     logging.config.dictConfig(logging_config) 

    configure_logging() # MainProcess 
    def pool_initializer(): 
     configure_logging() 

    n_cores = 4 
    pool = mp.Pool(n_cores, initializer=pool_initializer) 
    pool.map(do_log, range(100)) 
    pool.close() 
    pool.join() 

अब, कार्यकर्ता प्रक्रियाओं को एक अपने व्यक्तिगत लॉग फाइल करने के लिए लॉग इन करेंगे, और अब मुख्य प्रक्रिया के stderr StreamHandler का उपयोग करेगा:

यहाँ एक उदाहरण है।

2

सबसे सरल जवाब यह है कि आपको शायद multiprocessing के साथ ग्लोबल्स को संशोधित करने से बचना चाहिए। ध्यान दें कि रूट लॉगजर, जिसे आप logging.getLogger() का उपयोग करते हैं, वैश्विक है।

इसके आसपास सबसे आसान तरीका बस प्रत्येक प्रक्रिया के लिए एक नया logging.Logger उदाहरण बना रहा है। आप प्रक्रियाओं के बाद उन्हें नाम कर सकते हैं, या बस बेतरतीब ढंग से:

log= logging.getLogger(str(uuid.uuid4()))

तुम भी how should I log while using multiprocessing in python

+0

ठीक है, मैं चाहता हूं कि प्रत्येक प्रक्रिया एक नई फाइल पर लॉग इन करे। यही कारण है कि मैं लॉगर कॉन्फ़िगरेशन का उत्तराधिकारी नहीं बनना चाहता हूं। इसके अलावा उपयोगकर्ता परिभाषित लॉगर्स का एक गुच्छा है जो पहले से मौजूद है। तो लॉगर्स न केवल मेरे ऊपर हैं ;-)। इसके अलावा, मैं अभी भी एक लॉगिंग पदानुक्रम प्राप्त करने में सक्षम होना चाहता हूं, इसलिए 'लॉग = logging.getLogger (str (uuid.uuid4())) कुछ निश्चित रूप से काम नहीं करेगा। – SmCaterpillar

+0

@ एसएम कैटरपिलर आप उचित हैंडलर सेट करके प्रत्येक लॉगजर आउटपुट को एक अलग फ़ाइल में रख सकते हैं। मैं आपको सलाह देता हूं कि विभिन्न प्रक्रियाओं पर एक सामान्य लॉगिंग पदानुक्रम न हो - आपको एक इंटर-प्रोसेस लॉकिंग तंत्र को स्वयं लागू करने की आवश्यकता होगी (विवरण के लिए मैंने जो उत्तर दिया है उसे देखें) – goncalopp

+0

अभी भी विश्वास नहीं है :-)। मुझे पदानुक्रम क्यों नहीं रखना चाहिए? मुद्दा यह है कि मेरे पास सिम्युलेटर की तरह कुछ है (उससे अधिक, मूल रूप से एक सिम्युलेटर फ्रेमवर्क) जो अलग-अलग पैरामीटर सेटिंग्स चलाता है, आमतौर पर सिंगल कोर। हालांकि, चूंकि सभी पैरामीटर रन स्वतंत्र होते हैं, इसलिए मैं समय-समय पर मल्टीप्रोसेसिंग पर स्विच कर सकता हूं। इस प्रकार, मैं अपने लॉगिंग हैंडलिंग और लॉगर पदानुक्रम को फिर से लिखना नहीं चाहता, लेकिन बस इसे मल्टीप्रोसेसिंग के साथ काम करें। मुझे यह विचार पसंद है कि प्रत्येक प्रक्रिया एक अलग फ़ाइल में लॉग इन होती है। हालांकि, अगर मैं उस के लिए भी जाता हूं, तो मेरे पुराने हैंडलर अभी भी फोर्किंग के कारण बने रहते हैं :-( – SmCaterpillar

0

आप जरूरत तो कार्यकर्ता प्रक्रियाओं में विरासत में मिला होने से प्रवेश पदानुक्रम को रोकने के लिए, बस लॉगिंग विन्यास कार्यकर्ता पूल बनाने के बाद है।आपके उदाहरण से:

pool = mp.Pool(n_cores) 
logging.basicConfig(format=format, level=logging.INFO) 

फिर, कुछ भी विरासत में नहीं मिलेगा।

अन्यथा, जैसा कि आपने कहा, os.fork() की वजह से, चीजें विरासत/डुप्लीकेट हो जाएंगी। इस मामले में, पूल बनाने के बाद आपके विकल्प लॉगिंग को पुन: कॉन्फ़िगर कर रहे हैं (मेरा अन्य उत्तर देखें), या अन्य (सुझाव) सुझाव/उत्तर।

संबंधित मुद्दे