6

新しいdefaultdictプロキシオブジェクトを実装する際に問題が発生しました。 documentationはちょっと恐ろしいので、私はこれについて正しく行く方法がわかりません。サブクラス化multiprocessing.managers.BaseProxy

Managerインスタンスから利用できるタイプのリストにdefaultdictを追加したいとします。あなたはので、私は、私はその後、defaultdictを収容するためにmultiprocessing.managers.BaseProxyの私のサブクラスを作成しmultiprocessing.mangers.BaseManager

class Manager(BaseManager): 
    pass 

から自分のスタブマネージャーを作った(私が最初にどのだろう葯スタブを持ってみたの株式multiprocessing.ManagerManager.registerメソッドを使用することはできませんサブクラスdefaultdictBaseProxyそれが動作していないようでした、両方がここで私は、現在持っているものです:。

class ProxyDefaultDict(BaseProxy): 
    def __init__(self, default_factory=None, *args, **kwargs): 
     self.__data = defaultdict(default_factory) 
     super().__init__(*args, **kwargs) 

    def _callmethod(self, methodname, args=(), kwds={}): 
     return getattr(self.__data, methodname)(*args, **kwds) 

    def _getvalue(self): 
     return self.__data.copy() 

    def __repr__(self): 
     return self.__data.__repr__() 

    def __str__(self): 
     return self.__data.__str__() 

Manager.register('defaultdict', ProxyDefaultDict) 

最終目標は、安全にプロセスやスレッド間でキーロックを共有する共有辞書を持っている彼。

  1. BaseManagerのサブクラスは、コンテキストマネージャすなわち経由initalizableだけのようだ:

    if __name__ == '__main__': 
        m = Manager() 
        d = m.defaultdict(m.Lock) 
        with d['named_lock']: 
         print('holding the lock') 
    

    しかし、私はいくつかの問題をヒットしました:再I画像、それが初期化される方法の一例ですwith Manager() as m。この場合、m = Manager()を使用します(multiprocessing.Managerのとおり)。世界の終わりではなく、なぜこれが当てはまるのか不思議であり、それがサインであれば私は何かを間違ってやっています。

  2. サブクラスmultiprocessing.managers.BaseManagerまた、デフォルトの登録値はmultiprocessing.Managerです。この場合、私は自分のマネージャーのためにProxyLockを再登録する必要があります(これは、これを行うための予期した方法もわかりません)。 multiprocessing.Managerを直接サブクラス化するのは安全ですか?

  3. 最後に、私のProxyDefaultDictは、自分が__init__をきれいに上書きすることを許可していないようです。そして私はサブクラス化するときにBaseProxy.__init__と呼ばないのが嫌です。問題は、BaseProxyも位置引数を受け入れることです。私は、これはラウンドの方法は、default_factory引数をキー付き引数のみにすることですが、期待されるインターフェイスをdefaultdictに変更して、私がここで間違って何かをやっていると仮定するようにしています。 Manager.Lockのような他のタイプは、位置的な引数を受け入れることができるようです。

ありがとうございました。

答えて

3

ソースコードを表示したら、それを少し変更するだけで問題なく(デフォルトのDictProxyの作成方法に基づいて)defaultdict型のプロキシを取得できます。

from collections import defaultdict 

from multiprocessing.managers import MakeProxyType, SyncManager 

DefaultDictProxy = MakeProxyType("DefaultDictProxy", [ 
    '__contains__', '__delitem__', '__getitem__', '__len__', 
    '__setitem__', 'clear', 'copy', 'default_factory', 'fromkeys', 
    'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 
    'update', 'values']) 

SyncManager.register("defaultdict", defaultdict, DefaultDictProxy) 
# Can also create your own Manager here, just using built in for simplicity 

if __name__ == '__main__': 
    with SyncManager() as sm: 
     dd = sm.defaultdict(list) 
     print(dd['a']) 
     # [] 

個人的には、既に提供されているツールを使用することで、自分でサブクラス化する方法についても心配する必要はありません。

しかし、あなたが探しているデフォルトのロックシナリオを作成することはできません。マルチプロセッシング・ロックは継承されるように設計されているため、一般的にロックは暗号化できません。これは、プロキシを介して転送されるデータ型の要件です。例:

from multiprocessing import Lock 

    m = SyncManager() 
    m.start() 
    d = m.defaultdict(Lock) 
    print(d['named_lock']) 
    m.shutdown() 

は、ランタイムエラーが発生します:あなたは `SyncManager`ではなく、` Manager`、おかげで `register`を呼び出すことができるように

RuntimeError: Lock objects should only be shared between processes through inheritance 
+0

ああうん、そうです。ロックをデフォルトとして使用しようとすると、別のエラーが表示されます。たとえば、管理されたロックを使用しようとしているとき。 'm.defaultdict(m.Lock)' 'TypeError:セキュリティ上の理由からAuthenticationStringオブジェクトを取り除くことができません.'というエラーが出ます。管理されていないロックを使用すると、「直列化不可能なメッセージ」が返されます( '#RETURN'、)。 Python 3.4で動く私はロックが過塩素酸になる可能性があると考えていたでしょう。 – freebie

+0

ええ、私は3.6がちょうど更新されたエラー/検出方法を持っていると思います。スレッドロックを使用しようとすると、同じエラーが表示されます。これを回避するには、https://stackoverflow.com/questions/17960296/trouble-using-a-lock-with-multiprocessing-pool-pickling-errorという他のアイデアがあります。 – CasualDemon