我的ASP .Net C#Web应用程序允许其用户使用FTP将我的服务器上的帐户中的文件发送到任何远程服务器。我已经实现了一个WCF服务来执行此操作。该服务为每个用户实例化一个类,该类生成一个在服务器上执行FTP操作的工作线程。客户端向服务发送命令,服务找到分配给客户端的工作线程并启动FTP命令。然后,客户端每两秒轮询一次该服务以获取FTP操作的状态。当客户端发送“disconnect”命令时,执行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实例?
答案 0 :(得分:2)
实际上,这里的第一个问题是同步对此静态对象的访问。 Dictionary<TKey, TValue>
不是线程安全的,因此您必须确保只有一个线程同时访问它。因此,您应该在lock
中包含对该字典的每次访问,假设您当然有正在编写的方法和正在阅读的其他方法。如果您只是在阅读,则不需要同步。就单身人士是可扩展性的敌人而言,这实际上是一种夸张的陈述,如果没有特定的情况就毫无意义。这实际上取决于确切的场景和实施。在您的示例中,您只显示了一个词典=&gt;所以我们可以说的是,你需要确保没有线程正在读取这个字典而其他正在编写,并且在其他线程正在读取时没有线程正在写入该字典。
例如在.NET 4.0中,您可以使用ConcurrentDictionary<TKey, TValue>
类,在这种情况下是线程安全的。
有一件事是肯定的:虽然单例模式可能会或可能不会成为可伸缩性的敌人,具体取决于具体的实现,但单例模式是孤立的单元可测试性的主要敌人。
答案 1 :(得分:1)
如果您打算使用单例,我建议您还将ConcurrencyMode设置为ConcurrencyMode.Multiple。例如......
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public class UserFtpService : IUserFtpService
{
}
如果不这样做,您的WCF服务将是一个单例,但一次只允许一个线程访问,这肯定会影响性能。当然,您需要确保集合的线程安全性(如前面提到的答案)。