1

マルチプロセッシング マネージャーを介して複合構造を共有しようとしていますが、複合クラス メソッドの 1 つだけを使用しようとすると、「 RuntimeError: maximum recursion depth exceeded 」という問題が発生しました。

クラスはcode.activestateのトークンであり、マネージャーに含める前に私がテストしました。

クラスをプロセスに取得し、そのaddChild()メソッドを呼び出すとき、プロセスの外では動作している間、 RunTimeErrorを保持しました。

複合クラスは ** ____getattr()____ ** メソッドを実装する SpecialDict クラスから継承します。

addChild()の呼び出し中に、python のインタープリターが別の ** ____getattr()____ ** を探す可能性があります。これは、正しいものがマネージャーによってプロキシされていないためですか?

もしそうなら、そのクラス/メソッドへのプロキシを作成する正しい方法は私には明らかではありません

次のコードは、この状態を正確に再現します。

1) これは manager.py です:

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()

AlberT によって提案された CompositeDict() クラスのプロキシを実行する方法に関するこの関連する質問を見てください。

tgrayによって提供される解決策は機能しますが、競合状態を回避することはできません

4

3 に答える 3

0

問題は、オブジェクトを管理する方法をマネージャーに指示する必要があることだと思います。これは、標準のPythonタイプではありません。

他の世界では、CompositeDictのプロキシを作成する必要があります

例としてこのドキュメントを見ることができます:http://ruffus.googlecode.com/svn/trunk/doc/html/sharing_data_across_jobs_example.html

于 2009-09-25T11:05:40.920 に答える
0

Python のデフォルトの最大再帰深度は 1000 (または 999、忘れました...) です。ただし、デフォルトの動作は次のように変更できます。

import sys
sys.setrecursionlimit(n)

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())

これをすべて 1 つのファイルにまとめましたが、分割しても問題はありません。

が更新されchild_nameていることを確認できるように、消費者に引数を追加しました。CompositDict

オブジェクトには getterとsetter の両方があることに注意してくださいCompositDict。私がゲッターしか持っていなかったとき、各コンシューマーはCompositDict子を追加したときに上書きしていました。

これが、Consumer クラス内のセッターとゲッターにアクセスする必要があるため、登録済みのメソッドをget_sharedではなく に変更した理由です。get_comp

また、「永久に役立つ」ため、マネージャープロセスに参加したくないと思います。BaseManager のソース (./Lib/multiprocessing/managers.py:Line 144) を見ると、この関数によって、またはserve_forever()によってのみ中断される無限ループに陥ることがわかります。KeyboardInterruptSystemExit

要するに、このコードは (私が知る限り) 再帰ループなしで機能しますが、それでもエラーが発生する場合はお知らせください。

于 2009-09-24T19:27:23.377 に答える
0

クラス間に循環参照がある可能性はありますか? たとえば、外部クラスには複合クラスへの参照があり、複合クラスには外部クラスへの参照があります。

マルチプロセッシング マネージャーはうまく機能しますが、大規模で複雑なクラス構造がある場合、型/参照を正しくシリアル化できないというエラーが発生する可能性があります。もう 1 つの問題は、マルチプロセッシング マネージャーからのエラーが非常にわかりにくいことです。これにより、障害状態のデバッグがさらに困難になります。

于 2009-09-24T21:23:40.627 に答える