Python 带有垃圾收集的惰性计算

Python lazy computing with garbage collection

给定:

  1. 一组用于计算相互依赖变量的计算
  2. 从变量中选择的一组所需输出

我愿意:

  1. 只计算我需要的变量(惰性计算)
  2. 每个变量最多计算一次(缓存)
  3. 摆脱输出或剩余输出计算(垃圾收集)中不再需要的变量
  4. 奖励:对计算进行排序,以便首先删除要删除的最大变量,以将内存使用量减少到最大值

例如:

    a = 1
    b = 2
    c = b ** 10
    d = a + b

在这个例子中:

  1. 如果 a 是唯一需要的输出,那么 bcd 永远不需要计算
  2. 如果需要cd,那么b应该只计算一次
  3. 如果需要 cd,那么 a 可以在计算 d 后立即忘记
  4. 由于 a 最终可以被垃圾收集,我们尝试尽快安排,因此首先计算 d(或者如果 [=28,我们应该从 c 开始=] 操作会不会暂时占用更多内存?这个不是很确定...)

在编写上述计算时,作为简单的语句序列,未观察到属性 1 和 4。

同时,可以使用 @property:

获得属性 1 和 3(缺少 2 和 4)
    class DataGetter:
        @property
        def a(self): return 1
        @property
        def b(self): return 2
        @property
        def c(self): return self.b ** 10
        @property
        def d(self): return self.a + self.b

同样,可以使用 @cached_property:

获得属性 1 和 2(缺少 3 和 4)
    class DataGetter:
        @cached_property
        def a(self): return 1
        @cached_property
        def b(self): return 2
        @cached_property
        def c(self): return self.b ** 10
        @cached_property
        def d(self): return self.a + self.b

有没有办法确保满足所有前 3 个属性? (也可能是第 4 个?)

如果我们将每个变量包装在一个实例中,那么可以通过lambda:延迟计算来实现惰性,并且可以以正常方式实现缓存。由于 lambda 是闭包,每个都将包含“单元格”,这些单元仅保留 lambda 实际使用的外部函数的局部变量(参见 ),从而允许垃圾收集按需工作。

class LazyValue:
    def __init__(self, f):
        self._f = f
    @cached_property
    def value(self):
        v = self._f()
        self._f = None
        return v

需要设置 self._f = None 才能使垃圾收集按预期工作;如果已经计算了一个值,那么我们不需要或不想保留对 self._f 关闭的任何其他 LazyValue 实例的引用。

用法:

def compute():
    a = LazyValue(lambda: 1)
    b = LazyValue(lambda: 2)
    c = LazyValue(lambda: b.value ** 10)
    d = LazyValue(lambda: a.value + b.value)
    # return whichever results are required
    return d

print(compute().value) # 3