2011-08-07 18 views
43

非デーモンのpythonプールを作成することは可能でしょうか?私は、プール内に別のプールを持つ関数を呼び出せるようにしたい。ありがとう。Python Process Pool非デーモンですか?

+0

私の知る限りをインポートし、それが__injectすることはできませんdependency__、BTW私はあなたの質問の2番目の部分を理解していません。私は、プール内に別のプールがある関数を呼び出すことができるようにして、労働者がデーモン化されているという事実を妨げる方法を理解しています。 – mouad

+1

関数aに関数bを実行するプールがあり、関数cを実行するプールがある場合、bにはデーモンプロセスで実行されており、デーモンプロセスはプロセスを作成できないという問題があります。 'AssertionError:デーモンプロセスは子供を持つことができません ' – Max

答えて

68

multiprocessing.pool.Poolクラスは鬼神のそれらを作り、それらを開始し、その__init__方法でワーカープロセスを作成し、それらが開始されている(そしてその後それはもう許されていない)の前に、Falseに自分daemon属性を再設定することはできません。しかし、独自のサブクラスmultiprocesing.pool.Poolmultiprocessing.Poolは単なるラッパー関数です)を作成して、独自のmultiprocessing.Processサブクラス(これは常にデーモンではない)をワーカープロセスに使用することができます。

ここでは、これを行う方法の完全な例を示します。重要な部分は、NoDaemonProcessMyPoolの2つのクラスで、最後に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

上記のコードは私のためにぶら下がっているようです。具体的には、work()内のpool.close()でハングしているようです。私は行方不明のものはありますか? –

+1

LinuxとPython 2.6/2.7/3.2 OS XでPython 2.7/3.2(print行を修正した後)で自分のコードをもう一度テストしました。LinuxとPython 2.7/3.2はOS X上でうまく動作しますが、 OS X(Lion)上のPython 2.6で動作します。これは修正されたマルチプロセッシングモジュールのバグだと思われますが、実際にはバグトラッカーをチェックしていません。 –

+0

これは実際にはマルチプロセッシングモジュールで修正する必要があります(非デーモンワーカーのオプションが利用可能である必要があります)。誰がそれを維持しているか知っていますか? –

6

multiprocessingモジュールは、プロセスまたはスレッドとプールを使用するにはすてきなインターフェイスを持っています。あなたの現在のユースケースによっては、外側のプールにmultiprocessing.pool.ThreadPoolを使用することを検討すると、プロセスではなくのスレッドを(内部からプロセスを起動できるスレッド)にします。作成したとしてそれはGILによって、私の特定のケース(私は両方をテストした)、プロセスの起動時間に外Poolから制限される可能性があります

hereははるかThreadPoolでソリューションを上回ります。


それはThreadsためProcessesを交換するのはとても簡単です。 ThreadPoolソリューションの使用方法の詳細については、hereまたはhereをご覧ください。

0

問題はモジュール間でグローバルをインポートしようとしたときに発生し、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   
関連する問題