1

我正在尝试通过多处理管理器共享复合结构,但在尝试仅使用一种复合类方法时,我感到“ RuntimeError: maximum recursion depth exceeded ”有问题。

该类是来自code.activestate的令牌,并在包含到管理器之前由我测试。

在将类检索到进程中并调用其addChild()方法时,我保留了RunTimeError,而在进程之外它可以工作。

复合类继承自一个 SpecialDict 类,该类实现了一个 ** ____getattr()____ ** 方法。

有可能在调用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 的默认最大递归深度为 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())

我在一个文件中完成了所有这些,但你应该没有任何问题来分解它。

child_name向您的消费者添加了一个参数,以便我可以检查是否CompositDict正在更新。

请注意,您的对象既有 getter有 setter 。CompositDict当我只有一个吸气剂时,每个消费者在CompositDict添加一个孩子时都会覆盖它。

这就是为什么我还将您的注册方法更改为,get_shared而不是get_comp,因为您将希望在您的 Consumer 类中访问 setter 和 getter。

另外,我认为您不想尝试加入您的经理流程,因为它将“永远服务”。如果您查看 BaseManager 的源代码(./Lib/multiprocessing/managers.py:第 144 行),您会注意到该serve_forever()函数将您置于仅由KeyboardInterruptor中断的无限循环中SystemExit

底线是这段代码在没有任何递归循环的情况下工作(据我所知),但如果您仍然遇到错误,请告诉我。

于 2009-09-24T19:27:23.377 回答
0

类之间是否可能存在循环引用?例如,外部类有一个对复合类的引用,而复合类有一个对外部类的引用。

多处理管理器运行良好,但是当您拥有大型、复杂的类结构时,您可能会遇到无法正确序列化类型/引用的错误。另一个问题是来自多处理管理器的错误非常神秘。这使得调试失败条件更加困难。

于 2009-09-24T21:23:40.627 回答
0

我认为问题在于您必须指示经理如何管理您的对象,这不是标准的 python 类型。

在其他世界中,您必须为您创建一个代理 CompositeDict

您可以查看此文档作为示例:http ://ruffus.googlecode.com/svn/trunk/doc/html/sharing_data_across_jobs_example.html

于 2009-09-25T11:05:40.920 回答