我的 WCF 服务可以使用单例进行扩展吗?
我的 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 实例?
My ASP .Net C# web application allows its users to send files from their account on my server to any remote server using FTP. I have implemented a WCF service to do this. The service instantiates a class for each user that spawns a worker thread which performs the FTP operations on the server. The client sends a command to the service, the service finds the worker thread assigned to the client and starts the FTP commands. The client then polls the service every two seconds to get the status of the FTP operation. When the client sends the "disconnect" command, the class and the worker thread doing the FTP operations is destroyed.
The FTP worker thread needed to persist between the client's queries because the FTP processing can take a long time. So, I needed a way for the client to always get the same instance of the FTP class between calls to the service. I implemented this service as a singleton, thus:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class UserFtpService : IUserFtpService
{
private SortedDictionary<string, UserFTPConnection> _clients = new SortedDictionary<string, UserFTPConnection>();
...
}
Where "UserFTPConnection" is the class containing the worker thread and the user's account name is used for the indexing in the dictionary.
The question I have is this: In the books I have read about WCF, the singleton instance is called "the enemy of scalability." And I can see why this is so. Is there a better way to make sure the client gets the same instance of UserFTPConnection between queries to the WCF service other than using a singleton?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
实际上,您的第一个问题是同步对此静态对象的访问。
Dictionary
不是线程安全的,因此您必须确保只有一个线程同时访问它。因此,您应该将对这个字典的每次访问包装在一个lock
中,当然假设您有正在写入的方法和其他正在读取的方法。如果您只想阅读,则无需同步。至于单例是可扩展性的敌人,这确实是一个夸张的说法,并且在没有特定场景的情况下毫无意义。这实际上取决于确切的场景和实施。在您的示例中,您只显示了字典 =>所以我们只能说,您需要确保在其他线程正在写入时没有线程正在从此字典中读取,并且在其他线程正在读取时没有线程正在写入该字典。例如,在 .NET 4.0 中,您可以使用
ConcurrentDictionary
类在这种情况下是线程安全的。但有一件事是肯定的:虽然单例模式可能会也可能不会成为可扩展性的敌人,具体取决于具体的实现,但单例模式是孤立的单元可测试性的大敌。
Actually here your first problem is synchronizing the access to this static object.
Dictionary<TKey, TValue>
is not thread safe so you must ensure that only one thread is accessing it at the same time. So you should wrap every access to this dictionary in alock
, assuming of course you have methods that are writing and others that are reading. If you are only going to be reading you don't need to synchronize. As far as singleton being the enemy of scalability, that's really an exaggerated statement and pretty meaningless without a specific scenario. It would really depend on the exact scenario and implementation. In your example you've only shown a dictionary => so all we can say is that you need to ensure that no thread is reading from this dictionary while other is writing and that no thread is writing to this dictionary while other thread is reading.For example in .NET 4.0 you could use the
ConcurrentDictionary<TKey, TValue>
class which is thread safe in situations like this.One thing's for sure though: while the singleton pattern might or might not be an enemy of scalability depending on the specific implementation, the singleton pattern is the arch-enemy of unit testability in isolation.
如果您要使用单例,我建议还设置 ConcurrencyMode 到 ConcurrencyMode.Multiple。例如...
如果你不这样做,你的WCF服务将是一个单例,但一次只允许一个线程访问,这肯定会影响性能。当然,您需要确保集合的线程安全(如前面提到的答案)。
If you are going to use a singleton, I'd recommend also setting ConcurrencyMode to ConcurrencyMode.Multiple. For example...
If you don't do this, your WCF service will be a singleton but only allow one thread to access at a time, which would certainly effect performance. Of course you will need to ensure thread safety of collections (as in previously mentioned answer).