简体   繁体   English

懒惰的单例初始化

[英]lazy initialization of singletons

While reading Jon Skeet's article on singletons in C# I started wondering why we need lazy initialization in a first place. 在阅读Jon Skeet关于C#中单例的文章时,我开始想知道为什么我们首先需要延迟初始化。 It seems like the fourth approach from the article should be sufficient, here it is for reference purposes: 似乎文章中的第四种方法应该足够了,这里仅供参考:

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;
        }
    }
}

In the rare circumstances, where you have other static methods on a singleton, lazy initialization may have benefits, but this is not a good design. 在极少数情况下,在单例上有其他静态方法,延迟初始化可能有好处,但这不是一个好的设计。

So can people enlighten me why lazy initialization is such a hot thing? 那么人们可以告诉我为什么懒惰的初始化是如此热门的事情?

In those scenarios where whatever it is you are initializing might not be needed at all, and is expensive to initialize, (in terms of CPU cycles or resources), then implementing a lazy initializor saves that cost in those cases where the object is not required. 在那些可能根本不需要初始化的情况下,并且初始化成本很高(在CPU周期或资源方面),然后实现延迟初始化可以在不需要对象的情况下节省成本。 。

If the object will always be required, or is relatively cheap to initialize, then there is no added benefit from a lazy initializer. 如果始终需要该对象,或者初始化相对便宜,那么延迟初始化器没有额外的好处。

In any event, implementing a lazy initializer improperly can make a singleton non-thread-safe, so if you need this pattern, be careful to do it correctly. 在任何情况下,不正确地实现惰性初始化程序可以使单例非线程安全,因此如果您需要此模式,请小心正确执行。 Jon's article has a pattern, (I think it's the last one), that addresses this issue. Jon的文章有一个模式,(我认为这是最后一个),解决了这个问题。

You don't need lazy initialization on a singleton, if the only reason you're going to use that type is to reference the instance. 如果您要使用该类型的唯一原因是引用该实例,则不需要在单例上进行延迟初始化。

If, however, you reference any other property or method on the type, or the type itself, you will initialize the singleton. 但是,如果您在类型或类型本身上引用任何其他属性或方法,则将初始化单例。

Granted, good design would leave one task for one type, so this shouldn't be a problem. 当然,好的设计会为一种类型留下一个任务,所以这应该不是问题。 If you make your singleton class to "complex", however, lazy initialization can help keep you from having consequences due to initializing too soon. 但是,如果将单例类设置为“复杂”,则延迟初始化可以帮助您避免由于过早初始化而导致的后果。

I'm not sure that this applies to C# as well, but I'll answer for C++: 我不确定这也适用于C#,但我会回答C ++:

One of the ideas behind Singletons is that the order of initialization of static objects is undefined. Singletons背后的一个想法是静态对象的初始化顺序是不确定的。 So if you have a static class that tries to use another static class, you might be in trouble. 因此,如果您有一个试图使用另一个静态类的静态类,您可能会遇到麻烦。

A concrete example: Let's say I have a Log class, which I decided to implement as a Singleton. 一个具体的例子:假设我有一个Log类,我决定将其作为Singleton实现。 Let's also assume I have a method called LoadDB, which for whatever reason, is a static called at the start of the program. 我们还假设我有一个名为LoadDB的方法,无论出于何种原因,它都是在程序开始时调用的静态。 Assuming LoadDB decides it needs to log something, it will call the Singleton. 假设LoadDB决定它需要记录某些内容,它将调用Singleton。 But since the order of static initialization is undefined, it might be doing something that's an error. 但由于静态初始化的顺序未定义,因此它可能正在做一些错误。

A Singleton fixes this, since once you call GetInstance(), no matter where you are in the initialization process, the object is guaranteed to exist. Singleton修复此问题,因为一旦调用GetInstance(),无论您在初始化过程中的哪个位置,都保证该对象存在。

Again, I don't know if this is relevant, but at least that's the history of it (as far as I remember). 同样,我不知道这是否相关,但至少这是它的历史(据我记得)。

From Java DI perspective, lazy initialization is good, there are always (say, spring) beans in another API that you might not want to use, for example, an eagerly loaded singleton cache (something that is shared with everyone using the cache) might not be needed for you although it may be referred as a dependency in your same code. 从Java DI的角度来看,延迟初始化很好,在你可能不想使用的另一个API中总有(例如,spring)bean,例如,一个急切加载的单例缓存(与使用缓存的每个人共享的东西)可能虽然它可能在同一代码中被称为依赖项,但您并不需要它。 Whats the point in loading the singleton wasting resources? 加载单身浪费资源的重点是什么?

The lazy initialization implementation choice is tricky, in spring, would you choose lazy-init="true" (spring eagerly instantiates singletons), an init-method/destroy-method, @PostConstruct, InitializingBean - afterPropertiesSet() method or return same spring instance in a getInstance() method? 懒惰的初始化实现选择很棘手,在春天,你会选择lazy-init =“true”(spring急切地实例化单例),init-method / destroy-method,@ PostConstruct,InitializingBean - afterPropertiesSet()方法或返回相同的弹簧getInstance()方法中的实例?

The choice is a tradeoff of testability over reusability outside the spring container. 选择是可测试性与弹簧容器外的可重用性的权衡。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM