原子复制对象属性

时间:2014-08-01 19:32:06

标签: python object copy tuples

我有一个不断变化的对象,与我的程序无关。

因此,例如,我的data会在一些随机但很小的间隔后不断更新。

现在我想在某个时间t复制这个对象的某些属性。如何在不复制整个对象的情况下确保我的操作是原子的? data还有其他一些我不感兴趣的值。

以下是代码段:

def get_values(self):
        if self.data:
            return (self.data.a, self.data.b, self.data.c)
        else:
            return (0, 0, 0)

在此,我只关注data.adata.bdata.c。我想将这些值作为get_values中的元组返回。这是原子的吗?这是否保证a,b,c值在时间上是一致的?最好的方法是什么?

2 个答案:

答案 0 :(得分:0)

使用锁。多消费者/单生产者锁是好的,但互斥体也可以作为概念验证。只需在更改之前对对象进行写锁定,可以使用Python同步,也可以使用某些外部内容(如FS锁),并在更新后释放它。消费者在读取对象之前应该先读取锁定对象,但只要他们不释放读锁定,他们就可以确保它保持一致。

如果你不能,你有选择,但它们取决于你如何修改对象。

  1. 如果您的对象检索外部数据,例如abc是吸引者从文件系统中读取内容,在每次访问时,您必须确保它们是一致的。制作一种方法,从外部来源一次阅读abc,并使用它而不是属性访问。

  2. 如果更新代码也是Python,并且它在与您相同的解释器中运行,那么除非更新程序使用ctype witchery,否则您都受GIL的约束。 Python可以抢先将你的线程转换为在你将它包装成元组的过程中改变你的对象的东西,你可以做的事情并不多。在这种情况下,我会先看看如何暂时禁用抢占(例如,在你的线程上强行保持GIL),但这肯定不会是纯粹的Python解决方案。

  3. 使用RCU。如果data是指向要更新的对象的唯一指针,则可以事先创建data个实例,并快速将self.data引用与您自己的伪造新实例交换,同时保持旧的data对象存活并可供您分析。然后,外部流程将更新新的data。您可以分两步完成此操作:

    new_data = Data() # create data object, but it's
                      # invisible to anyone except you now
    
    old_data = self.data # active object captured, but can
                         # still be updated in the middle,
                         # so unsafe to use now
    
    self.data = new_data # done! now all changes go to
                         # new_data, and old_data is
                         # available for you to inspect it
    
  4. 如果您的对象不仅包含abc,而且还有一些昂贵的复制状态,您可以实现类似于Javascript原型设计的内容,结合RCU方法,以及一些无锁编程。

    所以,你有一个对象,持有"快照"的无锁双链表,最顶层的快照是你当前的状态,每个都保存对下一个和前一个状态的引用(除了那些列表的头部和尾部)。您从单个快照开始,是空对象。

    拦截使用__setattr__写入您的对象,并无条件地更新最顶级状态。

    为了安全地从对象中读取数据,您必须创建新的空状态并将其附加到双链接快照列表的末尾,有效地重定向所有后续写入,同时保持先前状态不变;并记住对拍摄快照时最顶端的状态快照的引用。

    然后,要读取每个值,首先要记住最上面的状态,然后查看它是否具有所需名称的值。如果没有,则下降到链接列表中的上一个快照,然后重复,直到找到该值或到达底部。您可以使用__getattr__使这种方法透明。

    完成分析后,您可能需要节省内存。通过将所有状态快照从下到上合并为一个状态对象,将其附加到快照列表,然后清除所有阴影快照。

答案 1 :(得分:-1)

Python中的数字,字符串和元组是不可变的;使用扩充分配将重新绑定名称。

您的其他类型只是变异,并保持相同的对象。

所以它确实是一个副本。