2011-08-07 12 views
43

क्या एक पाइथन पूल बनाना संभव नहीं है जो गैर-डिमनिक है? मैं चाहता हूं कि एक पूल एक ऐसे समारोह को कॉल करने में सक्षम हो जिसमें एक और पूल हो। धन्यवाद।पायथन प्रोसेस पूल गैर-डिमनिक?

+0

AFAIK, कोई यह संभव नहीं है सभी पूल में कार्यकर्ता daemonized रहे हैं और यह __inject संभव नहीं है निर्भरता__, बीटीडब्लू मैं आपके प्रश्न के दूसरे भाग को समझ नहीं पा रहा हूं, 'मैं चाहता हूं कि एक पूल एक ऐसे समारोह को कॉल करने में सक्षम हो जिसमें एक और पूल है' और यह कैसे इस तथ्य में हस्तक्षेप करता है कि मजदूरों को निंदा किया जाता है। – mouad

+1

क्योंकि अगर फ़ंक्शन में एक पूल होता है जो फ़ंक्शन बी चलाता है जिसमें एक पूल होता है जो फ़ंक्शन सी चलाता है, बी में कोई समस्या है कि यह एक डेमॉन प्रक्रिया में चल रहा है, और डेमॉन प्रक्रियाएं प्रक्रियाएं नहीं बना सकती हैं। 'AssertionError: बच्चों को – Max

उत्तर

68

multiprocessing.pool.Pool वर्ग, अपने __init__ विधि में कार्यकर्ता प्रक्रियाओं बनाता है उन्हें भूत का बनाता है और उन्हें शुरू होता है, और यह करने के लिए अपने Falsedaemon विशेषता फिर से स्थापित करने के लिए संभव नहीं है इससे पहले कि वे शुरू कर रहे हैं (और बाद में इसे अब और अनुमति नहीं है)। लेकिन आप multiprocesing.pool.Pool (multiprocessing.Pool केवल एक रैपर फ़ंक्शन है) का अपना उप-वर्ग बना सकते हैं और कार्यकर्ता प्रक्रियाओं के लिए उपयोग किए जाने वाले अपने स्वयं के multiprocessing.Process उप-वर्ग को प्रतिस्थापित कर सकते हैं, जो हमेशा गैर-डिमनिक होता है।

यहां यह करने का एक पूर्ण उदाहरण है। महत्वपूर्ण भाग शीर्ष पर NoDaemonProcess और MyPool दो वर्ग हैं और अंत में MyPool उदाहरण पर pool.close() और pool.join() पर कॉल करने के लिए हैं।

#!/usr/bin/env python 
# -*- coding: UTF-8 -*- 

import multiprocessing 
# We must import this explicitly, it is not imported by the top-level 
# multiprocessing module. 
import multiprocessing.pool 
import time 

from random import randint 


class NoDaemonProcess(multiprocessing.Process): 
    # make 'daemon' attribute always return False 
    def _get_daemon(self): 
     return False 
    def _set_daemon(self, value): 
     pass 
    daemon = property(_get_daemon, _set_daemon) 

# We sub-class multiprocessing.pool.Pool instead of multiprocessing.Pool 
# because the latter is only a wrapper function, not a proper class. 
class MyPool(multiprocessing.pool.Pool): 
    Process = NoDaemonProcess 

def sleepawhile(t): 
    print("Sleeping %i seconds..." % t) 
    time.sleep(t) 
    return t 

def work(num_procs): 
    print("Creating %i (daemon) workers and jobs in child." % num_procs) 
    pool = multiprocessing.Pool(num_procs) 

    result = pool.map(sleepawhile, 
     [randint(1, 5) for x in range(num_procs)]) 

    # The following is not really needed, since the (daemon) workers of the 
    # child's pool are killed when the child is terminated, but it's good 
    # practice to cleanup after ourselves anyway. 
    pool.close() 
    pool.join() 
    return result 

def test(): 
    print("Creating 5 (non-daemon) workers and jobs in main process.") 
    pool = MyPool(5) 

    result = pool.map(work, [randint(1, 5) for x in range(5)]) 

    pool.close() 
    pool.join() 
    print(result) 

if __name__ == '__main__': 
    test() 
+0

होने के लिए डिमनिक प्रक्रियाओं की अनुमति नहीं है उपरोक्त कोड मेरे लिए लटक रहा है। विशेष रूप से यह पूल (क्लोज़() के अंदर काम() में लटका हुआ प्रतीत होता है। क्या मुझसे कुछ छूट रहा है ? –

+1

मैंने अभी पाइथन 2.7/3.2 ("प्रिंट" लाइनों को ठीक करने के बाद) लिनक्स और पायथन 2.6/2.7/3.2 ओएस एक्स लिनक्स और पायथन 2.7/3.2 पर ओएस एक्स पर ठीक काम किया है लेकिन कोड वास्तव में लटका है ओएस एक्स (शेर) पर पायथन 2.6 के साथ। यह मल्टीप्रोसेसिंग मॉड्यूल में एक बग प्रतीत होता है, जो तय हो गया है, लेकिन मैंने वास्तव में बग ट्रैकर की जांच नहीं की है। –

+0

यह वास्तव में मल्टीप्रोसेसिंग मॉड्यूल में तय किया जाना चाहिए (गैर-डेमोनिक श्रमिकों के लिए एक विकल्प उपलब्ध होना चाहिए)। क्या कोई जानता है कि इसे कौन बनाए रखता है? –

6

multiprocessing मॉड्यूल प्रक्रियाओं या धागे के साथ पूल उपयोग करने के लिए एक अच्छा इंटरफ़ेस है। आपके वर्तमान उपयोग के मामले के आधार पर, आप अपने बाहरी पूल के लिए multiprocessing.pool.ThreadPool का उपयोग करने पर विचार कर सकते हैं, जिसके परिणामस्वरूप प्रक्रियाओं के विपरीत (जो भीतर से प्रक्रियाओं को फैलाने की अनुमति देता है)

यह Gil द्वारा सीमित किया जा सकता है, लेकिन मेरी विशेष मामले में के रूप में बनाया here दूर ThreadPool साथ समाधान अधिक महत्वपूर्ण बाहरी Pool से, प्रक्रियाओं के लिए स्टार्टअप समय (मैं दोनों का परीक्षण किया)।


यह वास्तव में Threads के लिए Processes स्वैप करने के लिए आसान है। ThreadPool समाधान here या here का उपयोग कैसे करें के बारे में और पढ़ें।

0

मुझे जिस मुद्दे का सामना करना पड़ा वह मॉड्यूल के बीच ग्लोबल्स आयात करने की कोशिश में था, जिससे प्रोसेसपूल() लाइन को कई बार मूल्यांकन किया जा सकता था।

globals.py

from processing    import Manager, Lock 
from pathos.multiprocessing import ProcessPool 
from pathos.threading  import ThreadPool 

class SingletonMeta(type): 
    def __new__(cls, name, bases, dict): 
     dict['__deepcopy__'] = dict['__copy__'] = lambda self, *args: self 
     return super(SingletonMeta, cls).__new__(cls, name, bases, dict) 

    def __init__(cls, name, bases, dict): 
     super(SingletonMeta, cls).__init__(name, bases, dict) 
     cls.instance = None 

    def __call__(cls,*args,**kw): 
     if cls.instance is None: 
      cls.instance = super(SingletonMeta, cls).__call__(*args, **kw) 
     return cls.instance 

    def __deepcopy__(self, item): 
     return item.__class__.instance 

class Globals(object): 
    __metaclass__ = SingletonMeta 
    """  
    This class is a workaround to the bug: AssertionError: daemonic processes are not allowed to have children 

    The root cause is that importing this file from different modules causes this file to be reevalutated each time, 
    thus ProcessPool() gets reexecuted inside that child thread, thus causing the daemonic processes bug  
    """ 
    def __init__(self): 
     print "%s::__init__()" % (self.__class__.__name__) 
     self.shared_manager  = Manager() 
     self.shared_process_pool = ProcessPool() 
     self.shared_thread_pool = ThreadPool() 
     self.shared_lock   = Lock()  # BUG: Windows: global name 'lock' is not defined | doesn't affect cygwin 

फिर सुरक्षित रूप से कहीं और से अपने कोड में आयात

from globals import Globals 
Globals().shared_manager  
Globals().shared_process_pool 
Globals().shared_thread_pool 
Globals().shared_lock   
संबंधित मुद्दे