单例模式 vs 缓存 ASP.NET

8

我在.NET中创建了一个Registry类,它是单例的。显然这个单例的行为就像被保存在缓存中一样(每个会话都可以访问单例对象)。这是一个好的实践还是应该将此单例添加到缓存中?同时,我需要注意GetInstance()函数的并发问题吗?

namespace Edu3.Business.Registry
{
    public class ExamDTORegistry
    {
        private static ExamDTORegistry instance;
        private Dictionary<int, ExamDTO> examDTODictionary;

        private ExamDTORegistry()
        {
            examDTODictionary = new Dictionary<int, ExamDTO>();
        }

        public static ExamDTORegistry GetInstance()
        {
            if (instance == null)
            {
                instance = new ExamDTORegistry();
            }
            return instance;
        }
    }
}
6个回答

6

你的GetInstance方法显然不是线程安全的 - 如果两个线程同时调用它,它们很可能会得到两个不同的实例。如果需要,我有一个有关实现单例模式的页面可以参考。

你的代码是否依赖于它是单例的?请记住,如果重新加载AppDomain,则会获得一个新实例。

但我确实看不出将对象放入缓存中有什么好处。你有特别想法吗?


是的,当AppDomain重新加载时,新实例没有问题。但是单例行为就像全局对象一样,不是吗?在测试时,我可以看到ASP.NET不会为每个会话创建单例,而只会为整个应用程序创建一个单例。 - Lieven Cardoen

5

尽管单例模式存在于GoF中,但通常被认为是不良实践。你希望仅有一个实例的原因是什么?


它在正确的地方使用是一个好的实践。不幸的是,我从来没有在真正“需要”的地方工作过,尽管我看到它们被实现了数百次 :)MonoState是一个很好的替代方案。 - Ben Scheirman
1
那么你需要一个缓存(不是单例,混淆两者很危险)。对于一个建议,请参见Ben在MonoState上的评论。否则,将缓存隐藏在数据层中。像NHibernate这样的好的O/R映射器已经支持这种事情了。 - user35149
另一个问题(抱歉打扰):这是否会导致性能问题?你可能会感到惊讶,但对于大多数现代数据库来说,200个请求相同的记录是轻而易举的。如果您遇到性能问题,我完全理解需要使用缓存。 - user35149
我跟你说实话,我是一名高级的 Flexer,现在已经学习 ASP.NET 一年半了。实际上,这是对一个存储过程的200个请求,非常密集。如果我使用 NHibernate 或 SubSonic 来完成它,单个请求需要处理几条记录。 - Lieven Cardoen
我看过MonoState,Singleton不就是一种只有一个静态变量的MonoState吗,这个变量就是实例本身吗? - Lieven Cardoen
显示剩余4条评论

3

HttpContext.Cache可以被所有会话访问,但是缓存中的项目可能会在过期或内存压力时从内存中删除。

HttpContext.Application也可供所有会话使用,是一个很好的存储持久化、应用程序范围对象的地方。

既然您已经创建了一个单例并且它起作用了,我不明白为什么要使用内置的单例集合之一,除非您需要Cache提供的额外功能。


1
那是什么额外的功能? - Lieven Cardoen
1
从内存中过期/移除项目。 - Greg

0

不太确定您所说的缓存是什么意思... 如果您想将其缓存(即... 将其保留在内存中,以便您无需再次从某个数据存储中获取它),那么是的,您可以将其放入缓存中,并且它将对所有用户全局可见。会话表示每个用户,因此我认为这不是您想要的。


0

我认为原始问题是询问哪种方法更好。如果您有保持静态或基本不可变的数据,则HTTP缓存或单例模式是很有意义的。如果单例在应用程序启动时加载,则根本没有“线程”问题。一旦单例就位,您将收到所请求的相同实例。我看到实际实现中的许多问题都是人们在没有充分考虑的情况下同时使用两者。为什么要使不可变配置数据过期?曾经有一个客户端在检查是否在缓存中时仍然创建ADO DB对象等。实际上,这两种解决方案都可以为您工作,但要获得任何积极效果,请确保使用缓存/单例。在任何情况下,如果您的数据不可用,则应立即刷新两者。


-1
我会这样写: private static final ExamDTORegistry instance;
这样你就不需要检查 NULL,而且它是线程安全的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接