【问题标题】:Will my WCF service be scaleable using a singleton?我的 WCF 服务是否可以使用单例进行扩展?
【发布时间】:2011-09-26 19:55:29
【问题描述】:

我的 ASP .Net C# Web 应用程序允许其用户使用 FTP 从他们在我的服务器上的帐户向任何远程服务器发送文件。我已经实现了一个 WCF 服务来做到这一点。该服务为每个用户实例化一个类,该类生成一个在服务器上执行 FTP 操作的工作线程。客户端向服务发送命令,服务找到分配给客户端的工作线程并启动 FTP 命令。然后客户端每两秒轮询一次服务以获取 FTP 操作的状态。当客户端发送“断开连接”命令时,执行 FTP 操作的类和工作线程被销毁。

FTP 工作线程需要在客户端查询之间持续存在,因为 FTP 处理可能需要很长时间。所以,我需要一种方法让客户端在对服务的调用之间始终获得相同的 FTP 类实例。我将此服务实现为单例,因此:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class UserFtpService : IUserFtpService
{
    private SortedDictionary<string, UserFTPConnection> _clients = new SortedDictionary<string, UserFTPConnection>();

    ...
}

其中“UserFTPConnection”是包含工作线程的类,用户的帐户名用于字典中的索引。

我的问题是:在我读过的有关 WCF 的书中,单例实例被称为“可伸缩性的敌人”。我明白为什么会这样。除了使用单例之外,有没有更好的方法来确保客户端在对 WCF 服务的查询之间获得相同的 UserFTPConnection 实例?

【问题讨论】:

    标签: asp.net wcf c#-4.0


    【解决方案1】:

    实际上你的第一个问题是同步访问这个静态对象。 Dictionary&lt;TKey, TValue&gt; 不是线程安全的,因此您必须确保只有一个线程同时访问它。因此,您应该将对该字典的每次访问都包装在lock 中,当然假设您有正在写入的方法和正在读取的其他方法。如果您只是要阅读,则不需要同步。至于单例是可扩展性的敌人,这确实是一种夸张的说法,如果没有特定的场景,那是毫无意义的。这实际上取决于确切的场景和实施。在您的示例中,您只显示了一个字典 =>,所以我们只能说,您需要确保没有线程正在从该字典中读取,而其他线程正在写入,并且没有线程正在写入该字典,而其他线程正在读取。

    例如,在 .NET 4.0 中,您可以使用 ConcurrentDictionary&lt;TKey, TValue&gt; 类,它在这种情况下是线程安全的。

    有一点是肯定的:虽然单例模式可能会或可能不会成为可扩展性的敌人,具体取决于具体的实现,但单例模式是孤立的单元可测试性的大敌。

    【讨论】:

    • 我没有显示其余代码,因为这与我的问题无关,但是对字典的访问是在“锁定”块内,因此可以正确同步。我的印象是“SortedDictionary”在查找条目时更快,这比插入或删除条目的速度更重要。我不知道 C# 中有任何排序的并发字典。
    • @Escovado,排序字典?从来没有听说过这样的事情。字典是一个哈希表,旨在执行键查找,没有为这些数据结构定义每个顺序或排序的概念。
    • 是的,SortedDictionary 在这里:msdn.microsoft.com/en-us/library/f7fta44c.aspx
    【解决方案2】:

    如果您要使用单例,我建议您也将ConcurrencyMode 设置为 ConcurrencyMode.Multiple。比如……

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public class UserFtpService : IUserFtpService
    {
    }
    

    如果您不这样做,您的 WCF 服务将是单例的,但一次只允许一个线程访问,这肯定会影响性能。当然,您需要确保集合的线程安全(如前面提到的答案)。

    【讨论】:

    • 感谢您的提示。一次一个线程是不可接受的。我是这些服务的新手。
    • 顺便说一句 - 您是否知道另一种(或更好的方法)来确保客户端获得相同的 UserFTPConnection 类实例,该实例在对服务器的请求之间持续存在?
    猜你喜欢
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多