为什么在twisted的pb系统中创建虚拟对象?

2024-05-29 11:38:14 发布

您现在位置:Python中文网/ 问答频道 /正文

如下所示,在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__,所以我根本看不出制作虚拟对象的意义。为什么要创建虚拟对象?你知道吗


Tags: to对象instanceselfnewreturnifinit
2条回答

这只是一个技巧,使必要的对象。创建一个完全任意的、用户定义类型的新实例比较困难。你把什么参数传递给它的__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的调用站点,在这里对同一个可缓存的重复引用被反序列化-每次都得到一个新的代理对象)。你知道吗

希望这更有意义!你知道吗

相关问题 更多 >

    热门问题