如下所示,在twisted.spread.flavors.RemoteCache.unjellyFor
中,我们创建了一个名为cProxy
的虚拟对象,并将其返回给客户机代码的其余部分,而不是返回self
。你知道吗
def unjellyFor(self, unjellier, jellyList):
if unjellier.invoker is None:
return setInstanceState(self, unjellier, jellyList)
self.broker = unjellier.invoker
self.luid = jellyList[1]
cProxy = _newDummyLike(self)
# XXX questionable whether this was a good design idea...
init = getattr(cProxy, "__init__", None)
if init:
init()
unjellier.invoker.cacheLocally(jellyList[1], self)
cProxy.setCopyableState(unjellier.unjelly(jellyList[2]))
# Might have changed due to setCopyableState method; we'll assume that
# it's bad form to do so afterwards.
self.__dict__ = cProxy.__dict__
# chomp, chomp -- some existing code uses "self.__dict__ =", some uses
# "__dict__.update". This is here in order to handle both cases.
self.broker = unjellier.invoker
self.luid = jellyList[1]
return cProxy
纽杜姆利克的身体看起来像这样:
def _newDummyLike(instance):
"""
Create a new instance like C{instance}.
The new instance has the same class and instance dictionary as the given
instance.
@return: The new instance.
"""
if isinstance(instance.__class__, type):
# New-style class
dummy = _DummyNewStyle()
else:
# Classic class
dummy = _Dummy()
dummy.__class__ = instance.__class__
dummy.__dict__ = instance.__dict__
return dummy
因为虚拟对象cProxy
与“真实”对象共享它的__dict__
和__class__
,所以我根本看不出制作虚拟对象的意义。为什么要创建虚拟对象?你知道吗
这只是一个技巧,使必要的对象。创建一个完全任意的、用户定义类型的新实例比较困难。你把什么参数传递给它的
__init__
?如果__init__
有不良副作用呢?也许您可以使用它的__new__
方法来代替-但是这需要什么参数呢?或者它甚至没有__new__
方法,或者__new__
有副作用。。。等等与解决所有这些问题相比,这是一个非常简单和直接的窍门。你知道吗
这些“虚拟”对象的目的是分布式垃圾收集。你知道吗
首先,让我们考虑一个
Copyable
的简单例子。每次序列化它时,您的对等方都会得到一个新的RemoteCopy
。很简单-没什么可跟踪的。您的Copyable
可以随时轻松地进行垃圾收集。你知道吗接下来,
Referenceable
。每次序列化它时,您的对等方都会得到一个新的RemoteReference
。现在我们有一个问题:如果你的同龄人仍然有RemoteReference
,他们应该能够调用你的Referenceable
上的方法,这意味着你的代理现在拥有对你的Referenceable
的强引用。稍微复杂一些,但仍然相当简单:每次RemoteReference
被垃圾收集时,在RemoteReference.__del__
中,我们发送一条decref
消息,告诉发送者他们的Referenceable
不再被引用。当计数为零时,强引用可能被消除,它将被自然地垃圾收集。这是因为RemoteReference
实际上是不可变的—它只包含有问题的对象的不透明标识符、对代理的引用,其他什么都没有。你知道吗最后,
Cacheable
。在这里我们遇到了一个真正的难题。您序列化了您的Cacheable
,现在Broker
需要维护对Cacheable
的强引用,以便能够判断稍后是否再次发送相同的Cacheable
。但是在另一端,RemoteCache
也有一个来自它的代理的强引用,因为Cacheable
可能需要向RemoteCache
发送更新。你知道吗这是一个循环引用,也是一个不好的引用。我们需要一些方法来打破循环性,这样我们交给应用程序的东西(被垃圾收集)就会跟踪服务器每次给我们发送的
RemoteCache
的不同副本。事实证明,我们可以做到这一点,并打破循环引用(记住,这段代码早于python的GC!)通过haivng一个单独的实例对象,每个实例对象都有自己的__del__
方法,用于跨每个RemoteCache
发送。但是我们可以通过给共享内部状态的应用程序对象(__dict__
)来保持一致性的幻觉,而不让具有__del__
的对象通过让它们参与一个循环而变得不可收集。这样,当RemoteCache
对象被垃圾收集时,它们各自发送一条消息,我们将“真实的”对象(self
在您的示例中)与来自代理的强引用一起保留,它将成为“zeroteh”引用,这就是为什么它第一次被复制的原因(你可以看到只有一个_newDummyLike
的调用站点,在这里对同一个可缓存的重复引用被反序列化-每次都得到一个新的代理对象)。你知道吗希望这更有意义!你知道吗
相关问题 更多 >
编程相关推荐