我有一个包含数千个整数的查找表(LUT),我根据从数据库中提取的内容计算了大量的请求。
如果我只是创建一个标准单例来保存LUT,它是否会在请求之间自动保留,还是我需要将其推送到应用程序状态?
如果它们是自动保留的,那么将它们与Application状态存储有什么区别?
正确的单例实现如何?它不需要懒惰地初始化,但它需要是线程安全的(每个服务器实例有数千个理论用户)并且具有良好的性能。
编辑:Jon Skeet的第四个版本看起来很有希望http://csharpindepth.com/Articles/General/Singleton.aspx
public sealed class Singleton
{
static readonly Singleton instance=new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
{
}
Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
// randomguy's specific stuff. Does this look good to you?
private int[] lut = new int[5000];
public int Compute(Product p) {
return lut[p.Goo];
}
}
答案 0 :(得分:2)
我不会依赖于请求之间保持静态。 [在请求之间重置进程的过程总是存在,尽管不太可能。]我建议使用HttpContext的Cache对象来保持请求之间的共享资源。
答案 1 :(得分:2)
是的,静态成员仍然存在(与持久性不一样 - 它不是“保存”,它永远不会消失),其中包括单例的实现。您可以免费获得一定程度的延迟初始化,就好像它是在静态赋值或静态构造函数中创建的,在首次使用相关类之前不会调用它。该创建默认锁定,但所有其他用途必须是线程安全的,如你所说。鉴于所涉及的并发程度,那么除非单例是不可变的(你的查找表在应用程序生命周期内没有改变)你必须非常小心你如何更新它(一种方式是假单身人士) - 在更新时,你创建一个新对象,然后锁定分配它来替换当前值;虽然它看起来像一个“从外面”,但不是严格的单例。)
最大的危险是引入全球状态的任何事情都是可疑的,特别是在处理像网络这样的无状态协议时。它可以很好地使用,特别是作为永久或接近永久数据的内存缓存,特别是如果它涉及一个无法从数据库中快速获得的对象图。
但是陷阱很大,所以要小心。特别是,锁定问题的风险不容低估。
编辑,以匹配问题中的修改:
我最担心的是阵列的初始化方式。很明显,这个例子是不完整的,因为每个项目只有0。如果它设置为初始化并且是只读的,那么很好。如果它是可变的,那么对你的线程非常非常小心。
还要注意太多此类查找对缩放的负面影响。虽然您在预先计算中保存了大多数请求,但是当更新单例时,效果是有一段非常繁重的工作。长期启动可能是可以容忍的(因为它不会经常发生),但随后发生的任意减速可能很难追查其来源。
答案 2 :(得分:0)
编辑:请参阅Jon关于只读锁定的评论。
我已经有一段时间了,因为我已经处理过单例(我更喜欢让我的IOC容器处理生命周期),但是这里是你如何处理线程安全问题。你需要锁定任何改变单身人士状态的东西。只读操作,例如Compute(int)
不需要锁定。
// I typically create one lock per collection, but you really need one per set of atomic operations; if you ever modify two collections together, use one lock.
private object lutLock = new object();
private int[] lut = new int[5000];
public int Compute(Product p) {
return lut[p.Goo];
}
public void SetValue(int index, int value)
{
//lock as little code as possible. since this step is read only we don't lock it.
if(index < 0 || index > lut.Length)
{
throw new ArgumentException("Index not in range", "index");
}
// going to mutate state so we need a lock now
lock(lutLock)
{
lut[index] = value;
}
}