Python: 如何传递一个 Autoproxy 对象
Python: How to pass an Autoproxy object
我需要将一个对象的代理传递给另一个对象,但每当我这样做时,所有其他对象得到的都是代理的引用,而不是代理本身。这与我正在尝试做的类似:
import multiprocessing.managers as m
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar)
self.manager.start()
self.bar = self.manager.Bar()
self.bar.set_proxy(self.bar)
class Bar(object):
def __init__(self):
self.proxy = None
def set_proxy(self, proxy):
self.proxy = proxy
class MyManager(m.BaseManager):
pass
test = Foo()
每当我这样做时,self.proxy
中的值是我创建的 Foo 实例,而不是管理器返回的代理。
这是因为设计缺陷,或者可能是 a bug,Proxy
实例被解封的方式。现在,如果 unpickling 代码看到你在 Manager
中 运行,它会在你 unpickle 时给你指示对象,而不是 Proxy
:
def RebuildProxy(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
If possible the shared object is returned, or otherwise a proxy for it.
'''
server = getattr(process.current_process(), '_manager_server', None)
if server and server.address == token.address:
return server.id_to_obj[token.id][0] # This returns the referent
else:
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds) # This returns the Proxy
有时这可能是可取的,但有时不是,就像您的情况一样。您可以通过替换在您的程序中执行 unpickling 的 ReduceProxy
函数来解决它:
import multiprocessing.managers as m
from multiprocessing import process
def RebuildProxyNoReferent(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
The Proxy object is always returned.
'''
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds)
m.RebuildProxy = RebuildProxyNoReferent # Monkey-patch it
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar)
self.manager.start()
self.bar = self.manager.Bar()
print(type(self.bar))
self.bar.set_proxy(self.bar)
class Bar(object):
def __init__(self):
self.proxy = None
def set_proxy(self, proxy):
print("got {}".format(type(proxy)))
self.proxy = proxy
class MyManager(m.BaseManager):
pass
test = Foo()
如果你不想猴子补丁,你也可以子类化 BaseProxy
,虽然它需要更多的工作:
import multiprocessing.managers as m
from multiprocessing.managers import BaseProxy
from multiprocessing import process
def RebuildProxyNoReferent(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
If possible the shared object is returned, or otherwise a proxy for it.
'''
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds)
class MyProxy(BaseProxy):
_exposed_ = ("set_proxy",)
def set_proxy(self, arg):
self._callmethod('set_proxy', (arg,))
def __reduce__(self):
ret = super(MyProxy, self).__reduce__()
# RebuildProxy is the first item in the ret tuple.
# So lets replace it, just for our proxy.
ret = (RebuildProxyNoReferent,) + ret[1:]
return ret
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar, MyProxy)
self.manager.start()
self.bar = self.manager.Bar()
print(type(self.bar))
self.bar.set_proxy(self.bar)
我需要将一个对象的代理传递给另一个对象,但每当我这样做时,所有其他对象得到的都是代理的引用,而不是代理本身。这与我正在尝试做的类似:
import multiprocessing.managers as m
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar)
self.manager.start()
self.bar = self.manager.Bar()
self.bar.set_proxy(self.bar)
class Bar(object):
def __init__(self):
self.proxy = None
def set_proxy(self, proxy):
self.proxy = proxy
class MyManager(m.BaseManager):
pass
test = Foo()
每当我这样做时,self.proxy
中的值是我创建的 Foo 实例,而不是管理器返回的代理。
这是因为设计缺陷,或者可能是 a bug,Proxy
实例被解封的方式。现在,如果 unpickling 代码看到你在 Manager
中 运行,它会在你 unpickle 时给你指示对象,而不是 Proxy
:
def RebuildProxy(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
If possible the shared object is returned, or otherwise a proxy for it.
'''
server = getattr(process.current_process(), '_manager_server', None)
if server and server.address == token.address:
return server.id_to_obj[token.id][0] # This returns the referent
else:
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds) # This returns the Proxy
有时这可能是可取的,但有时不是,就像您的情况一样。您可以通过替换在您的程序中执行 unpickling 的 ReduceProxy
函数来解决它:
import multiprocessing.managers as m
from multiprocessing import process
def RebuildProxyNoReferent(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
The Proxy object is always returned.
'''
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds)
m.RebuildProxy = RebuildProxyNoReferent # Monkey-patch it
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar)
self.manager.start()
self.bar = self.manager.Bar()
print(type(self.bar))
self.bar.set_proxy(self.bar)
class Bar(object):
def __init__(self):
self.proxy = None
def set_proxy(self, proxy):
print("got {}".format(type(proxy)))
self.proxy = proxy
class MyManager(m.BaseManager):
pass
test = Foo()
如果你不想猴子补丁,你也可以子类化 BaseProxy
,虽然它需要更多的工作:
import multiprocessing.managers as m
from multiprocessing.managers import BaseProxy
from multiprocessing import process
def RebuildProxyNoReferent(func, token, serializer, kwds):
'''
Function used for unpickling proxy objects.
If possible the shared object is returned, or otherwise a proxy for it.
'''
incref = (
kwds.pop('incref', True) and
not getattr(process.current_process(), '_inheriting', False)
)
return func(token, serializer, incref=incref, **kwds)
class MyProxy(BaseProxy):
_exposed_ = ("set_proxy",)
def set_proxy(self, arg):
self._callmethod('set_proxy', (arg,))
def __reduce__(self):
ret = super(MyProxy, self).__reduce__()
# RebuildProxy is the first item in the ret tuple.
# So lets replace it, just for our proxy.
ret = (RebuildProxyNoReferent,) + ret[1:]
return ret
class Foo(object):
def __init__(self):
self.manager = MyManager()
self.manager.register('Bar', Bar, MyProxy)
self.manager.start()
self.bar = self.manager.Bar()
print(type(self.bar))
self.bar.set_proxy(self.bar)