我正在尝试通过多处理管理器共享一个复合结构,但在尝试仅使用一个Composite类方法时,我感到遇到了“ RuntimeError:超出最大递归深度”的问题。
该类是来自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()
看看这个related questions如何为CompositeDict()类做代理 正如AlberT所建议的那样。
tgray 给出的解决方案有效,但无法避免竞争条件
答案 0 :(得分: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 和都是CompositDict
对象的setter。当我只有一个吸气剂时,每个消费者在添加孩子时都会覆盖CompositDict
。
这就是为什么我还将您的注册方法更改为get_shared
而不是get_comp
,因为您需要访问setter以及Consumer类中的getter。
此外,我认为您不想尝试加入您的经理流程,因为它将“永远服务”。如果查看BaseManager的源代码(./Lib/multiprocessing/managers.py:Line 144),您会注意到serve_forever()
函数会使您进入一个仅被{{1}打破的无限循环}或KeyboardInterrupt
。
底线是这段代码在没有任何递归循环的情况下工作(据我所知),但如果您仍然遇到错误,请告诉我。
答案 1 :(得分:0)
类之间是否有循环引用?例如,外部类具有对复合类的引用,复合类具有返回外部类的引用。
多处理管理器运行良好,但是当您拥有大型,复杂的类结构时,您可能会遇到无法正确序列化类型/引用的错误。另一个问题是来自多处理管理器的错误非常神秘。这使调试失败的条件更加困难。
答案 2 :(得分:0)
我认为问题在于你必须指示管理员如何管理你的对象,这不是标准的python类型。
在其他世界中,您必须为您创建一个代理CompositeDict
您可以查看此文档以获取示例:http://ruffus.googlecode.com/svn/trunk/doc/html/sharing_data_across_jobs_example.html