【问题标题】:C# Many instances of a Singleton objectC# Singleton 对象的许多实例
【发布时间】:2011-12-05 13:26:49
【问题描述】:

我遇到了单例模式的问题。

这真的很奇怪,但看起来我的单例模式有两三个实例。 我的网站是一个带有计时器的操作网站,我正在使用我的单例对象处理这些计时器和价格。

发生的情况是,有些人看到一些价格,而其他人在不同的网络中总是看到其他价格。

例如,在我的办公室,我的人看到一些拍卖价格为 0.56 美分,每个人看到的都一样,但在另一个网络中,例如我的房子,我看到 0.55 美分,而且计时器的值也不同。

话虽如此,我已经通过生成 GUID 并将其记录在我的日志文件中来测试我的 Singleton。这是一些代码

public class Singleton
{
    private static Singleton instance;
    private static System.Threading.Mutex mutex;

    System.Guid token;

    private Singleton() { 
        token = System.Guid.NewGuid();
        Logger.Log("New singleton Instance" + token.toString());
    }
    static Singleton()
    {
        instance = new Singleton();
        mutex = new System.Threading.Mutex();
    }

    public static Singleton Acquire()
    {
        mutex.WaitOne();
        return instance;
    }

    // Each call to Acquire() requires a call to Release()
    public static void Release()
    {
        mutex.ReleaseMutex();
    }

    public void SomeAction()
    {
       Logger.Log(token.toString() + " - SomeAction");
    }
}

在这段代码中,我在构造函数上生成令牌,并记录新单例的创建,然后...在SomeAction 方法中,我记录谁在执行该操作。

在此之后,我们进行了几次测试并下载了日志文件。

令我惊讶的是,我只看到一个正确的“New Singleton Instance bla”。但是随后,许多对 SomeAction 方法的调用使用不同的 GUID,这很奇怪。

我检查了对象仅在静态构造函数中创建,并且我还检查了任何地方都没有手动创建。

有关更多信息,这只发生在我的生产服务器上,这是一个 goDaddy 主机。我问过我的网站是否有多个应用程序池,他们说只有一个应用程序池。

【问题讨论】:

标签: c# singleton


【解决方案1】:

您的单例生命周期与 IIS 的当前工作进程相关联。

如果您配置了多个工作进程,则并非所有请求都由同一个进程处理,因此不是同一个单例。

【讨论】:

  • 这是有道理的,我会检查我有多少个工作进程...如果我有多个,你知道我怎样才能共享同一个单例实例吗?有可能吗?
  • 这绝对是我的问题,因为有多个工作进程我有多个单例对象...可悲的是我不能使用任何同步方法,因为我不能使用消息队列或远程处理...我正在尝试查看是否可以每 5 秒同步一次,但在某些情况下...等待的时间太长了 :(
【解决方案2】:

我不能肯定这是您的问题,但可能值得检查:

  • 如果在初始化日志框架之前创建实例,消息是被缓存还是被丢弃?我过去曾看到日志消息丢失,因为它们发生在日志初始化之前。
  • 您是否可能引用了包含此类的程序集的多个版本?这可能会导致每个程序集版本创建一个类的实例,因此看到的值将取决于调用它的代码。但是,这并不能解释您在从不同地理位置访问相同页面时看到的不同值的行为。
  • 如果可以的话,我也很想记录某种形式的unique machine id,以验证在一台机器上只运行此代码的一个副本。 “相信任何人,证明一切”在试图理解晦涩难懂的行为时是一种非常有用的启发式方法。

【讨论】:

  • 感谢您的回复!我将检查日志初始化,因此丢失这些消息可能是有意义的。是否可以在 bin 目录中拥有多个版本的同一个 dll?我的意思是我所有的 dll 都在我的 bin 文件夹中,而不是 GAC。
  • 我相信可以从同一个目录加载同一个程序集的多个版本,但是在重命名文件时需要一些技巧,所以你不太可能偶然做到这一点。跨度>
【解决方案3】:

您的网站可能只使用一个应用程序池,但一个应用程序池可能会产生多个主机进程。检查您的应用程序池的工作进程数。

【讨论】:

    【解决方案4】:

    问题可能是您实现的单例模式不是线程安全的。 因为在 Web 应用程序中,您同时运行了多个线程(工作进程),可能会发生两个线程创建您的类的两个不同实例的情况。 您还应该考虑您的网络应用程序在哪里运行。如果您已将 Web 应用程序部署在 Web 农场上,则可能会发生不同的 Web 服务器将您的类的不同实例作为静态变量“活”在 Web 服务器的内存中。

    【讨论】:

    • 感谢您的回复,在我的日志文件中,我看到不同的线程 ID 共享相同的令牌,所以我不认为这是线程问题.. 我也确保线程安全几乎在任何地方都使用锁和互斥锁!无论如何,我会进一步检查以确保它是线程安全的
    • 还要检查网络应用程序是否部署在网络农场上。在这种情况下,每个 Web 服务器都有一个实例
    【解决方案5】:

    您的静态构造函数似乎没有检查实例是否已创建。比如:

    static Singleton()
        {
        if (instance == null)
            {
            instance = new Singleton();
            mutex = new System.Threading.Mutex();
            }
        }
    

    应确保类中的其他方法实际上使用instance的相同“实例”。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    • 2010-10-05
    • 2014-08-11
    相关资源
    最近更新 更多