복붙노트

[PYTHON] 파이썬 프로세스 풀 비 데믹?

PYTHON

파이썬 프로세스 풀 비 데믹?

non-daemonic 인 python Pool을 생성 할 수 있습니까? 풀이 안에 다른 풀이있는 함수를 호출 할 수 있기를 원합니다.

나는 deamon 프로세스가 프로세스를 생성 할 수 없기 때문에 이것을 원한다. 특히 오류가 발생합니다.

AssertionError: daemonic processes are not allowed to have children

예를 들어, function_a에 function_c를 실행하는 풀이있는 function_b를 실행하는 풀이있는 시나리오를 생각해보십시오. function_b가 디먼 프로세스에서 실행 중이며 디먼 프로세스가 프로세스를 작성할 수 없기 때문에이 기능 체인이 실패합니다.

해결법

  1. ==============================

    1.multiprocessing.pool.Pool 클래스는 __init__ 메소드에 작업자 프로세스를 생성하고 데몬스트레이션을 시작하며 시작합니다. 시작하기 전에 자신의 데몬 속성을 False로 재설정 할 수 없습니다 (이후에는 더 이상 허용되지 않습니다). 그러나 multiprocessing.pool.Pool (multiprocessing.Pool은 래퍼 함수에 불과합니다)의 하위 클래스를 만들 수 있으며 자신의 다중 처리를 대신 사용할 수 있습니다. 작업 하위 프로세스에 항상 사용되는 하위 클래스는 비 데믹 (non-daemonic)입니다. .

    multiprocessing.pool.Pool 클래스는 __init__ 메소드에 작업자 프로세스를 생성하고 데몬스트레이션을 시작하며 시작합니다. 시작하기 전에 자신의 데몬 속성을 False로 재설정 할 수 없습니다 (이후에는 더 이상 허용되지 않습니다). 그러나 multiprocessing.pool.Pool (multiprocessing.Pool은 래퍼 함수에 불과합니다)의 하위 클래스를 만들 수 있으며 자신의 다중 처리를 대신 사용할 수 있습니다. 작업 하위 프로세스에 항상 사용되는 하위 클래스는 비 데믹 (non-daemonic)입니다. .

    다음은이를 수행하는 방법에 대한 전체 예제입니다. 중요한 부분은 상단에 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()
    
  2. ==============================

    2.다중 처리 모듈은 프로세스 나 스레드가있는 풀을 사용하기에 좋은 인터페이스를 가지고 있습니다. 현재 사용 사례에 따라 외부 Pool에 multiprocessing.pool.ThreadPool을 사용하는 것을 고려해 볼 수 있습니다. 스레드는 프로세스와 반대로 프로세스를 생성 할 수 있습니다.

    다중 처리 모듈은 프로세스 나 스레드가있는 풀을 사용하기에 좋은 인터페이스를 가지고 있습니다. 현재 사용 사례에 따라 외부 Pool에 multiprocessing.pool.ThreadPool을 사용하는 것을 고려해 볼 수 있습니다. 스레드는 프로세스와 반대로 프로세스를 생성 할 수 있습니다.

    그것은 GIL에 의해 제한 될 수도 있지만, 두 경우 모두 테스트 한 나의 특별한 경우에, 여기에 생성 된 바깥 쪽 풀의 프로세스 시작 시간은 ThreadPool을 사용한 솔루션보다 훨씬 큽니다.

    쓰레드를위한 프로세스를 바꾸는 것은 정말 쉽습니다. 여기 또는 여기에서 ThreadPool 솔루션을 사용하는 방법에 대해 자세히 읽어보십시오.

  3. ==============================

    3.내가 만난 문제는 ProcessPool () 행을 여러 번 평가하도록 모듈간에 전역 변수를 가져 오는 중 발생했습니다.

    내가 만난 문제는 ProcessPool () 행을 여러 번 평가하도록 모듈간에 전역 변수를 가져 오는 중 발생했습니다.

    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         
    
  4. from https://stackoverflow.com/questions/6974695/python-process-pool-non-daemonic by cc-by-sa and MIT license