【问题标题】:c# WebService kills Singleton it ownsc# WebService 杀死它拥有的 Singleton
【发布时间】:2015-09-01 19:51:39
【问题描述】:

我有一个 WebService,它拥有一个 Singleton:

public class WebService
{
    private static Singleton _singleton = Singleton.Instance;

    public void DoSomeJob(object jobObj) {
        _singleton.QueueJob(jobObj);
    }
}

.. 和单例,应该是线程安全的。

public static Singleton Instance
{
    get
    {
        lock (_syncRoot)
        {
            if (_instance == null)
                _instance = new Singleton();

            return _instance;
            }
        }
    }
}

我打算以这种方式实现的是,每个调用我的 WebService 的客户端都将其对象提供给同一个单例实例。同样,这个单例实际上并没有做更多的事情,只是在计时器滴答时将对象排队并处理它。

我面临(现在仍然是)的问题是,每次 WebService 终止时单例都会被杀死。但是,我不确定这是否会发生,因为 Singleton 的所有者正在被破坏,或者由于应用程序池设置给出的某种原因。 我试图让应用程序池在空闲时“始终运行”和“暂停”,而不是“按需”和“终止” - 没有成功:-/

为什么单身人士每次都被杀死?如何在 WebService 执行之间保持 Singleton 的实例处于活动状态?

【问题讨论】:

  • 实际上,我的帖子是从“大家好”开始的,但它一定是被剪掉了——请原谅 :)
  • 小心那些锁。并发请求将锁定在那段代码上。我知道这是您的意图,但并发请求应该是独立的,而不是排队等待轮到它。
  • 如果您正在寻找线程安全集合,请尝试一下:msdn.microsoft.com/en-us/library/…
  • @mitch 仅供参考,Stackoverflow 上的礼仪是以常见问题解答的方式撰写您的帖子,而不是论坛帖子或给其他网站用户的信函。考虑到这一点,我稍微编辑了您的问题。
  • @Mihai:谢谢你的链接!但是,你能指出为什么并发请求不应该排队等待吗?我必须承认我并不真正理解这一点。

标签: c# wcf singleton


【解决方案1】:

为什么单例每次都会被杀死?

您需要了解 WCF 如何管理服务instancing 才能了解这是为什么。默认情况下,WCF 将通过 session-enabled binding 为每个客户端创建一个新服务实例,如果不支持会话,则为每个调用创建一个新服务实例。

这意味着为处理客户端调用而调度的服务实例会将您的单例实例加载到内存中。但是,当客户端会话或单个调用(不支持会话)完成时,实例将被卸载,这意味着您的单例也将被卸载。

如何让 Singleton 的实例在 WebService 之间保持活动状态 处决?

有两种方法可以做到这一点:

  1. 摆脱你的单身。使用后备数据存储来跨多个客户端调用维护您的状态。
  2. 通过在服务实现声明中设置InstanceContextMode=InstanceContxtMode.Single 来使用单例服务实例。

在这两个选项中,我会选择选项 1。这是因为单例服务实例通常是一种反模式,因为它们 do not scale,并且只能在别无选择的情况下使用。

....考虑将排队功能实现到外部 组件,例如一个 Windows 服务,但为了简单起见 并降低复杂性我想在 网络服务

好的,我认为问题的根源就在这里。分布式系统有一个共同的信念,可以表述如下:

  • 简单 = 更少的组件,并且
  • 复杂 = 更多组件

我会将这种信念修改为:

  • 简单 = 简单组件,并且
  • 复杂 = 复杂的组件

在我看来,您决定将计时器/排队要求嵌入到 Web 服务中会自动使您的组件变得复杂。

我认为将从队列中读取的组件拆分为另一个组件正是您需要做的!

如果这让您望而生畏,那么我强烈建议您使用topshelf 来管理您的 Windows 服务,这是一个免费的框架,它使服务的创建和部署变得非常简单。

【讨论】:

  • 非常感谢您的详细回答,汤姆!关于你的选择,我完全同意你的看法。虽然我不知道选项 2 是一个已知的“反模式”,但在我写我的帖子之前,我已经决定反对这个解决方案。在我看来,没有理由让服务实例一直保持活动状态。这样做是一个快速的解决方案,但也是一个肮脏的解决方案。但是,选项 1 似乎也不是一个有效的解决方案,因为单例不用于跨不同请求共享数据。单例应该用于保持计时器运行..
  • @mitch - 嗯,我明白了。那么你能再解释一下这个计时器的用途吗?
  • 当然。每个服务客户端都应该给单例一个对象。单例应该将此对象添加到队列中。在提到的计时器的每个滴答声中,应该处理该队列的前 x 个对象。我还考虑过将排队功能实现到外部组件,例如一个 Windows 服务,但为了简单和降低复杂性,我想在 WebService 中实现它。
  • 我明白你的观点,汤姆,我在一定程度上同意。我的基本想法是,只要 Web 服务正在运行,就可以对对象进行排队和处理。这就是为什么我要直接将排队功能作为这个 Web 服务的一部分来实现的原因。将该功能外包给外部组件也意味着,即使 Web 服务甚至没有运行或者没有要处理的对象,计时器也在运行。为避免这种情况,我必须使两个组件相互通信,依此类推.. 评论太长了。非常感谢! :-)
  • @mitch - 只要网络服务正在运行,对象的排队和处理才是相关的 - 你如何定义“相关”?我不明白你在这里的推理。当 Web 服务未运行时,排队和处理组件上不会有任何活动。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多