什么样的功能是备忘录的候选者?

时间:2009-07-29 17:39:38

标签: c# memoization

我决定使用PostSharp(无法区分魔法)来读取属性和memoize functions。函数调用的哈希值将是键,并且将返回缓存(在Velocity)结果中,而不是再次调用该函数。容易腻,mac-and-cheesy。

我已经given up能够检测到装饰功能中的副作用,结果证明这是一个“难题”,即使对于专家来说也是如此,我当然不是。接下来,我必须弄清楚其他函数是否适合进行记忆。

  • 将复杂引用类型作为参数的方法怎么样?
  • 那些依赖于调用实例内部数据的方法呢?

最后一个想到了ActiveRecord-esque数据对象。

我是否需要重构一周的代码来支持memoization?

3 个答案:

答案 0 :(得分:4)

如果函数的所有输入都是值类型或不可变引用类型,如果它返回值类型或引用类型的新实例,并且它没有副作用,则只能记住该函数。周期。

记忆取决于输入和输出之间的确定性映射。每次调用F(a, b, c),其中a,b和c包含相同的值必须返回相同的结果,以便可以进行记忆。

如果参数是引用类型,那么即使它的值没有改变,使用它多次调用该函数也可能产生不同的结果。一个简单的例子:

public int MyFunction(MyType t)
{
   return t.Value;
}

Console.WriteLine(MyFunction(t));
t.Value++;
Console.WriteLine(MyFunction(t));

类似地,如果函数依赖于它外部的值,那么使用相同参数对该函数的多次调用可能会返回不同的结果:

int Value = 0;

public int MyFunction(int input)
{
   return Value;
}

Console.WriteLine(MyFunction(1));
Value++;
Console.WriteLine(MyFunction(1));

如果你的memoized函数除了返回值或新的引用类型之外还有其它功能,那么天堂会帮助你:

int Value = 0;

public int MyFunction(int input)
{
   Value++;
   return input;
}

如果你将该函数调用10次,Value将为10.如果你重构它以使用memoization然后再调用10次,Value将为1。

你可以开始着手解决如何记忆状态的问题,这样你就可以记下一个记忆参考类型的函数。但是你真正记得的是函数所依赖的一组值。您可以类似地破解具有副作用的memoized函数,以便在记忆之前发生其副作用。但这都是乞求麻烦。

如果要将memoization实现为采用引用类型的函数,正确的方法是重构仅适用于值类型的函数部分,并记住该函数,例如:

public int MyFunction(MyType t)
{
   return t.Value + 1;
}

到此:

public int MyFunction(MyType t)
{
   return MyMemoizableFunction(t.Value);
}

private int MyMemoizableFunction(int value)
{
   return value + 1;
}

实施memoization的任何其他方法,你采取a)做同样的事情,通过更加模糊的手段,或b)将无法工作。

答案 1 :(得分:3)

好吧,理论上,任何函数都是memoization的候选者。但是,请记住,memoization是关于交易空间的速度 -

通常,这意味着,为了计算答案,函数需要或依赖的状态越多,空间成本就越高,这降低了记忆方法的可取性。

您的两个示例基本上都是需要保存更多状态的情况。这有两个副作用。

首先,这需要更多的内存空间才能记住该功能,因为需要保存更多的信息。

其次,这可能会减慢memoized函数的速度,因为空间越大,答案查找的成本就越高,以及查找结果是否先前保存的成本就越高。< / p>

一般而言,我倾向于只考虑具有少量可能输入和低存储要求的功能,除非计算答案的成本非常高。

我知道这很模糊,但这是建筑“艺术性”的一部分。没有实现两个选项(memozied和non-memoized函数),分析和测量,没有“正确”的答案。

答案 2 :(得分:2)

您已经想到了一种提供AOP解决方案的方法,可以围绕函数Foo提供备忘录,那么还有什么可以搞清楚?

是的,您可以将任意复杂性的对象作为参数传递给memoized函数,只要它是不可变的,就像它依赖的所有东西一样。再说一次,目前静态发现并不容易。

您是否仍然坚持可以静态检查代码的想法,以便向用户提出“将备忘录应用于Foo是否一个好主意?”

如果您满足了自己的要求,那么您将参加到目前为止已经持续多年的全球研究工作。取决于你有多雄心勃勃,我想。