6

새로운 defaultdict 프록시 객체를 구현하는 데 문제가 있습니다. documentation은 약간 무서워서, 올바르게이 문제를 해결하는 방법을 모르겠습니다.서브 클래 싱하기 multiprocessing.managers.BaseProxy

Manager 인스턴스에서 사용할 수있는 유형 목록에 defaultdict을 추가하고 싶습니다. 당신은 defaultdict (내가 처음에하는 것 꽃밥 그루터기를 가진 시도 않았다 그때 multiprocessing.managers.BaseProxy의 내 서브 클래스가 수용하기 위해 만든 multiprocessing.mangers.BaseManager

class Manager(BaseManager): 
    pass 

에서 내가 만들어 놓은 재고 multiprocessing.Manager에 내 자신의 스텁 관리자를 Manager.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) 

최종 목표는 안전하게 프로세스와 스레드에서 키가 잠금을 공유하는 공유 사전을 가지고있다 그는를 나는 이미지가 초기화 될 방법의 예입니다 재 : 그러나

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

, 나는 몇 가지 문제에 충돌했습니다

  1. BaseManager의 서브 클래스는 컨텍스트 관리자 즉 통해서만 initalizable 것 같다 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 객체를 pickling 할 수 없습니다. '오류가 발생합니다. 관리되지 않는 잠금을 사용하면'직렬화 할 수없는 메시지가 발생합니다 ('#RETURN', ). Python 3.4에서 실행. 나는 자물쇠가 과산화물이 될 수 있다고 생각했을 것이다. – freebie

+0

그래, 나는 3.6이 업데이트 된 오류/탐지 방법을 가지고 있다고 생각한다. 스레딩 잠금을 사용하려고해도 동일한 오류가 발생합니다. 이 문제를 해결하기위한 다른 아이디어로는 https://stackoverflow.com/questions/17960296/trouble-using-a-lock-with-multiprocessing-pool-pickling-error가 있습니다. – CasualDemon

관련 문제