【发布时间】:2015-11-07 14:31:55
【问题描述】:
(抱歉,如果在其他地方回答了这个问题;这似乎是一个常见问题,但事实证明很难搜索,因为“线程”和“缓存”等术语会产生压倒性的结果。)
我有一个昂贵的计算,其结果被频繁访问但很少更改。因此,我缓存了结果值。这是我的意思的一些 c# 伪代码:
int? _cachedResult = null;
int GetComputationResult()
{
if(_cachedResult == null)
{
// Do the expensive computation.
_cachedResult = /* Result of expensive computation. */;
}
return _cachedResult.Value;
}
在我的代码的其他地方,我偶尔会将 _cachedResult 设置回 null,因为计算的输入已更改,因此缓存的结果不再有效,需要重新计算。 (这意味着我不能使用Lazy<T>,因为Lazy<T> 不支持被重置。)
这适用于单线程场景,但当然它根本不是线程安全的。所以我的问题是:使GetComputationResult 线程安全的最高效方法是什么?
显然我可以把整个东西放在一个 lock() 块中,但我怀疑可能有更好的方法? (可以进行原子检查以查看是否需要重新计算结果并仅在需要时才锁定的东西?)
非常感谢!
【问题讨论】:
-
线程偶尔获取陈旧值有多糟糕?
-
当一个线程正在计算而另一个线程想要得到结果时,你期望会发生什么?它应该等待还是获取旧值?
-
计算大概需要多少时间?
-
Lazy<T>无法重置,但您可以改用LazyInitializer.EnsureInitialized。当您希望它再次初始化时,只需将其设置为 null 即可。尽管您必须在此处使用包装器引用类型而不是可为空的。 -
只是,仅供参考,LazyInitializer 可能会多次调用初始化程序,但字段中会存储一个值。
标签: c# .net multithreading