为了好玩,我正在玩一个类来轻松缓存功能结果.基本的想法是你可以使用你想要的任何功能 - 虽然你只想将它用于相对昂贵的功能 - 并且可以轻松地将它包装起来使用相对便宜的字典查找,以便以后使用相同的参数运行.真的没什么可说的:
public class AutoCache<TKey, TValue>
{
public AutoCache(Func<TKey, TValue> FunctionToCache)
{
_StoredFunction = FunctionToCache;
_CachedData = new Dictionary<TKey, TValue>();
}
public TValue GetResult(TKey Key)
{
if (!_CachedData.ContainsKey(Key))
_CachedData.Add(Key, _StoredFunction(Key));
return _CachedData[Key];
}
public void InvalidateKey(TKey Key)
{
_CachedData.Remove(Key);
}
public void InvalidateAll()
{
_CachedData.Clear();
}
private Dictionary<TKey, TValue> _CachedData;
private Func<TKey, TValue> _StoredFunction;
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,还有一些额外的限制使得它没有那么有用.我们还可以添加一些功能以及实现的其他注意事项.我正在寻找有关如何改善以下任何一点的想法:
作为参考,如果我在实际代码中使用它,我认为最可能的地方是作为业务逻辑层的一部分,我使用此代码将数据访问层中的方法包装起来,只从中提取数据查找表.在这种情况下,相对于字典,数据库行程将是昂贵的,并且几乎总是只有一个"键"值用于查找,因此它是一个很好的匹配.
这种自动缓存功能结果的另一个名称是memoization.对于公共接口,请考虑以下几点:
public Func<T,TResult> Memoize<T,TResult>(Func<T,TResult> f)
Run Code Online (Sandbox Code Playgroud)
...并简单地使用多态来将T存储在对象的字典中.
扩展代表范围可以通过currying和部分功能应用来实现.像这样的东西:
static Func<T1,Func<T2,TResult>> Curry(Func<T1,T2,TResult> f)
{
return x => y => f(x, y);
}
// more versions of Curry
Run Code Online (Sandbox Code Playgroud)
由于Curry将多个参数的函数转换为单个参数的函数(但可能返回函数),因此返回值本身有资格进行memoization.
另一种方法是使用反射来检查委托类型,并将元组存储在字典中而不是简单地存储在参数类型中.一个简单的元组只是一个数组包装器,其哈希码和相等逻辑使用深度比较和散列.
弱引用可以帮助失效,但是使用WeakReference键创建字典很棘手 - 最好是在运行时的支持下完成(WeakReference值更容易).我相信那里有一些实现.
通过在内部字典上锁定突变事件可以轻松完成线程安全,但拥有无锁字典可以提高严重并发场景中的性能.那个字典可能更难创建 - 虽然这里有一个关于Java的有趣的演示文稿.
| 归档时间: |
|
| 查看次数: |
3619 次 |
| 最近记录: |