类型错误:AutoProxy对象不可迭代 - 多进程

10 投票
2 回答
4173 浏览
提问于 2025-04-16 17:48

考虑以下的服务器代码:

from multiprocessing.managers import BaseManager, BaseProxy

def baz(aa) :
    print "aaa"
    l = []
    for i in range(3) :
      l.append(aa)
    return l

class SolverManager(BaseManager): pass

manager = SolverManager(address=('127.0.0.1', 50000), authkey='mpm')
manager.register('solver', baz)

server = manager.get_server()
server.serve_forever()

还有相关的客户端:

import sys
from multiprocessing.managers import BaseManager, BaseProxy

class SolverManager(BaseManager): pass

def main(args) :
    SolverManager.register('solver')
    m = SolverManager(address=('127.0.0.1', 50000), authkey='mpm')
    m.connect()

    for i in m.solver(args[1]):
        print i

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

我觉得我在这里漏掉了一些重要的东西。我的猜测是我需要从BaseProxy类继承一个子类,以提供一个可迭代的对象,但到目前为止我还没能搞明白。

当我运行客户端时,我遇到了这个错误:

Traceback (most recent call last):
  File "mpmproxy.py", line 17, in <module>
    sys.exit(main(sys.argv))
  File "mpmproxy.py", line 13, in main
    for i in m.solver(args[1]):
TypeError: 'AutoProxy[solver]' object is not iterable

不过如果我尝试打印它,列表是存在的……也许这和客户端与服务器之间数据的序列化方式有关……

在文档中有一个类似的案例(使用生成器),他们用以下类来访问数据:

class GeneratorProxy(BaseProxy):
    _exposed_ = ('next', '__next__')
    def __iter__(self):
        return self
    def next(self):
        return self._callmethod('next')
    def __next__(self):
        return self._callmethod('__next__')

我是不是也应该做类似的事情?有没有人能给我一个例子并解释一下这是怎么回事?

更新

为了澄清:假设我添加了这个类:

class IteratorProxy(BaseProxy):
    def __iter__(self):
        print self
        return self

然后在客户端我注册这个函数为

SolverManager.register('solver', proxytype=IteratorProxy)

我得到的错误是:

$python mpmproxy.py test
['test', 'test', 'test']
Traceback (most recent call last):
  File "mpmproxy.py", line 22, in <module>
    sys.exit(main(sys.argv))
  File "mpmproxy.py", line 18, in main
    for i in m.solver(args[1]):
TypeError: iter() returned non-iterator of type 'IteratorProxy'

我感觉我在这里漏掉了一些简单的东西……

更新 2

我想我解决了这个问题:

关键是要获取真实的值:

for i in m.solver(args[1])._getvalue():
    print i

天哪!!!我不确定这是不是正确的答案,还是只是一个变通方法……

2 个回答

0

虽然OP在第二次更新中提到的解决方案可能有效,但方法 _getvalue() 是私有的,所以不应该这样访问。你可以试试使用列表代理类型(from multiprocessing.managers import ListProxy)。虽然从服务器返回的结果仍然不能被迭代,但据我所知,你应该能够使用大家都熟悉的 .pop().pop(i)(其中 i 是索引)来操作它,这些都是结果的公开方法。

0

没错,要让你的类可以被遍历,你需要定义一个叫做 __iter__ 的方法,这个方法是 BaseProxy 里定义的。所以,我觉得继承是个不错的选择!

撰写回答