【发布时间】:2012-01-11 15:12:10
【问题描述】:
使用我在Implementing the Singleton Pattern in C# 惊人的文章中判断为世界上最好的东西,我一直成功地使用以下类将用户定义的数据持久保存在内存中(对于很少修改的数据):
public class Params
{
static readonly Params Instance = new Params();
Params()
{
}
public static Params InMemory
{
get
{
return Instance;
}
}
private IEnumerable<Localization> _localizations;
public IEnumerable<Localization> Localizations
{
get
{
return _localizations ?? (_localizations = new Repository<Localization>().Get());
}
}
public int ChunkSize
{
get
{
// Loc uses the Localizations impl
LC.Loc("params.chunksize").To<int>();
}
}
public void RebuildLocalizations()
{
_localizations = null;
}
// other similar values coming from the DB and staying in-memory,
// and their refresh methods
}
我的用法如下所示:
var allLocs = Params.InMemory.Localizations; //etc
每当我更新数据库时,都会调用 RefreshLocalizations,因此只有部分内存存储被重建。我有一个单个 生产环境(大约 10 个),当调用 RefreshLocalizations 时,似乎表现不正常,根本不刷新,但这似乎也是间歇性的,非常完全奇怪。
我目前的怀疑是单例,我认为它做得很好,所有的单元测试都证明单例机制、刷新机制和 RAM 性能都按预期工作。
也就是说,我认为有这些可能性:
- 这位客户说他们的环境没有使用负载平衡是在撒谎,这是我不希望内存中的东西正常工作的设置(对吗?)
- 我正在测试他们的 IIS 中的一些非标准池配置(可能在 Web Garden 设置中?)
- 单例以某种方式失败,但不确定如何。
有什么建议吗?
.NET 3.5 所以没有太多可用的并行果汁,目前还没有准备好使用反应式扩展
Edit1:根据建议,吸气剂看起来像:
public IEnumerable<Localization> Localizations
{
get
{
lock(_localizations) {
return _localizations ?? (_localizations = new Repository<Localization>().Get());
}
}
}
【问题讨论】:
-
这里有可能你有一些线程安全问题吗?似乎您想要锁定以防止在刷新后创建存储库的多个实例(通常称为“缓存踩踏”)
-
从您的问题来看,听起来要发布的代码将是执行刷新的代码。你上面的东西在我看来没问题。负载平衡和 IIS 应该没有任何影响(但再次需要查看数据库刷新代码),除非您指的是多个网络服务器,在这种情况下,您需要在它们之间同步刷新(这种情况下只需使用外部缓存....AppFabric 缓存将是合适的)
-
@F.Aquino:实际上,不,它没有。很可能两个线程几乎同时尝试访问
Localization属性,从而导致创建了两个存储库。使这个属性线程安全将摆脱这个问题。换句话说:创建实例后,您的单例类不是线程安全的。 -
正如 Eric 所说,肯定可能存在一些线程问题,因为您没有锁定 _localizations 成员(以及 ?? 调用)。但是您说数据很少更新...您确定吗?
-
@F.Aquino 我应该补充一点,您应该修改您的 Singleton 以解决其他海报提到的线程问题,但我认为这不是您问题的根源。另外,您有什么理由不使用简单的静态类吗?如果您正在实现接口,或者需要从基类继承,单例可能很有用,但您似乎没有这样做,因此静态类可能同样有效。
标签: c# architecture .net-3.5 singleton