2009-09-24 5 views
1

다중 처리 관리자를 통해 복합 구조를 공유하려고하는데 Composite 클래스 중 하나만 사용하려고하면 "RuntimeError : 최대 재귀 깊이 초과"문제가 발생했습니다. 행동 양식.파이썬 다중 처리 관리자 및 복합 패턴 공유

클래스는 code.activestate의 토큰이며 관리자가 포함하기 전에 나를 테스트했습니다. 프로세스 외부에서 작동하면서

방법으로 클래스를 검색하고 그 하는 AddChild() 메소드를 호출

는 I은 RuntimeError에 보관.

복합 클래스는 ** __ getattr() __ ** ** 메서드를 구현하는 SpecialDict 클래스에서 상속합니다.

addChild()을 호출하는 동안 Python의 해석기가 관리자가 프록시를 사용하지 않았기 때문에 다른 ** __ getattr() ____ **을 검색 할 수 있습니까?

경우는

은 다음 코드는 바로이 조건을 재현 클래스/메소드에 프록시를 만들기 위해 올바른 방법으로 나에게 분명하지 않도록 :

이는 manager.py입니다)

1

from multiprocessing.managers import BaseManager 
from CompositeDict import * 

class PlantPurchaser(): 

    def __init__(self): 
     self.comp = CompositeDict('Comp') 

    def get_cp(self): 
     return self.comp 

class Manager(): 

    def __init__(self): 

     self.comp = QueuePurchaser().get_cp() 

     BaseManager.register('get_comp', callable=lambda:self.comp) 

     self.m = BaseManager(address=('127.0.0.1', 50000), authkey='abracadabra') 
     self.s = self.m.get_server() 

     self.s.serve_forever() 

2)이 consumer.py에 복합을 사용하려면 :

from multiprocessing.managers import BaseManager 

class Consumer(): 

    def __init__(self): 

     BaseManager.register('get_comp') 

     self.m = BaseManager(address=('127.0.0.1', 50000), authkey='abracadabra') 
     self.m.connect() 

     self.comp = self.m.get_comp() 
     ret = self.comp.addChild('consumer') 

3)는 controller.py 모든 발사를 실행 : 알버트에 의해 제안

from multiprocessing import Process 

class Controller(): 
    def __init__(self): 
     for child in _run_children(): 
      child.join() 

def _run_children(): 

    from manager import Manager 
    from consumer import Consumer as Consumer 

procs = (
     Process(target=Manager, name='Manager'), 
     Process(target=Consumer, name='Consumer'), 
     ) 

for proc in procs: 
    proc.daemon = 1 
    proc.start() 
return procs 

c = Controller() 

가보고 CompositeDict에 프록시 작업을 수행하는 방법에 대한이 related questions() 클래스 을 가져 가라.

tgray 작품에 의해 주어진 솔루션하지만 피할 수없는 경쟁 조건

+0

당신은 어떤 방법으로 코드를 변경나요 : 당신은 당신이

당신은 예를 들어이 문서에서 볼 수 있었다 CompositeDict에 프록시를 만들 필요가 다른 세계에서

.activestate? 클래스를 프로세스로 가져 오는 관련 코드를 게시 한 다음 addChild() 메서드를 호출 할 수 있습니까? – tgray

+0

복합 코드는 절대 변경되지 않습니다. 관련 코드로 업데이트 할 예정입니다 .... – DrFalk3n

+1

2 개의 하위 프로세스 만 필요합니까? 코드를 실행할 때 실패 할 때까지 계속해서 프로세스를 시작합니다. – tgray

답변

0

파이썬 1000의 기본 최대 재귀 깊이가 (또는 999을, 나는 ... 잊지). 하지만 thusly 히 기본 동작을 변경할 수 있습니다 n 당신이 허용 할 재귀의 수입니다

import sys 
sys.setrecursionlimit(n) 

.

편집 :

위의 대답은 (코멘트에 지적)이 문제의 근본 원인을 해결하기 위해 아무것도하지 않는다. 의도적으로 1000 번 이상 재귀하는 경우에만 사용해야합니다. 무한 루프 (이 문제와 같이)에 있다면, 결국 당신이 설정 한 한계를 치게 될 것입니다.

import sys 
from multiprocessing import Process 
from multiprocessing.managers import BaseManager 
from CompositDict import * 

class Shared(): 
    def __init__(self): 
     self.comp = CompositeDict('Comp') 

    def get_comp(self): 
     return self.comp 

    def set_comp(self, c): 
     self.comp = c 

class Manager(): 
    def __init__(self): 
     shared = Shared() 
     BaseManager.register('get_shared', callable=lambda:shared) 
     mgr = BaseManager(address=('127.0.0.1', 50000), authkey='abracadabra') 
     srv = mgr.get_server() 
     srv.serve_forever() 

class Consumer(): 
    def __init__(self, child_name): 
     BaseManager.register('get_shared') 
     mgr = BaseManager(address=('127.0.0.1', 50000), authkey='abracadabra') 
     mgr.connect() 

     shared = mgr.get_shared() 
     comp = shared.get_comp() 
     child = comp.addChild(child_name) 
     shared.set_comp(comp) 
     print comp 

class Controller(): 
    def __init__(self): 
     pass 

    def main(self): 
     m = Process(target=Manager, name='Manager') 
     m.daemon = True 
     m.start() 

     consumers = [] 
     for i in xrange(3): 
      p = Process(target=Consumer, name='Consumer', args=('Consumer_' + str(i),)) 
      p.daemon = True 
      consumers.append(p) 

     for c in consumers: 
      c.start() 
     for c in consumers: 
      c.join() 
     return 0 


if __name__ == '__main__': 
    con = Controller() 
    sys.exit(con.main()) 

나는 모든 이런 짓을 :

실제 문제가 단순히 내가하고 내가 무엇을 믿는에 구축 할 수로 스크래치 시작, 내가 다시 쓴 코드를 해결하기 위해 당신이 원하는 하나의 파일에 있지만 문제를 해결하는 데는 어려움이 없어야합니다.

고객에게 child_name 인수를 추가하여 CompositDict이 업데이트되었는지 확인했습니다.

CompositDict 개체에는 getter 세터가 있습니다. 게이머 만 가져 왔을 때 각 소비자는 자식을 추가 할 때 CompositDict을 덮어 씁니다.

그래서 소비자 클래스의 getter와 setter에 액세스하려는 경우 get_comp 대신 등록 된 메서드를 get_shared으로 변경했습니다.

또한 나는 "영원히 봉사 할 것"이므로 관리자 프로세스에 참여하려고하지 않는다고 생각합니다. BaseManager (./Lib/multiprocessing/managers.py:Line 144)의 소스를 보면 serve_forever() 함수를 사용하면 KeyboardInterrupt 또는 SystemExit만으로 끝나는 무한 루프에 빠질 수 있습니다.

결론이 코드는 반복적 인 루핑 없이는 작동하지만 오류가 여전히 발생하는 경우 알려 주시기 바랍니다.

+0

네, 그렇지만 이런 식으로 문제를 피할 수는 없으며 그 원인을 주장하지도 않습니다! – DrFalk3n

+0

이것은 문제를 숨길 수있는 경우에도 원인을 근절하지 않습니다. – drAlberT

+0

정확합니다. 전체 문제를 이해하지 않고 너무 빨리 대답했습니다. – tgray

0

클래스 사이에 순환 참조가있을 수 있습니까? 예를 들어 외부 클래스에는 복합 클래스에 대한 참조가 있고 복합 클래스에는 외부 클래스에 대한 참조가 있습니다.

다중 처리 관리자는 잘 작동하지만 크고 복잡한 클래스 구조가있는 경우 유형/참조를 올바르게 직렬화 할 수없는 오류가 발생할 수 있습니다. 다른 문제는 다중 처리 관리자의 오류가 매우 드문 경우입니다. 이로 인해 디버깅 실패 조건이 훨씬 더 어려워집니다.

+0

타입/레퍼런스가 제대로 직렬화되지 않아서 비틀 거 리기 쉽습니다. 예, 디버깅하기가 어렵습니다. 예를 들어 순환 참조가 아니거나 적어도 분명하지는 않습니다. +1 내 질문에 대한 관심 :-) – DrFalk3n

관련 문제