2011-09-26 73 views
0

我的ASP.Net C#Web應用程序允許其用戶使用FTP將來自我服務器上帳戶的文件發送到任何遠程服務器。我已經實現了一個WCF服務來做到這一點。該服務爲每個產生工作線程的用戶實例化一個類,該工作線程在服務器上執行FTP操作。客戶端向服務發送命令,服務找到分配給客戶端的工作線程並啓動FTP命令。然後,客戶端每兩秒輪詢一次服務以獲取FTP操作的狀態。當客戶端發送「disconnect」命令時,類和執行FTP操作的工作線程被銷燬。我的WCF服務可以使用單例可縮放嗎?

FTP工作線程需要在客戶端的查詢之間保留,因爲FTP處理可能需要很長時間。所以,我需要一種方法讓客戶始終在對服務的調用之間獲得相同的FTP類實例。我實現了這個服務作爲一個單身,這樣的:

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

    ... 
} 

其中「UserFTPConnection」是包含工作線程和用戶的帳戶名是用於字典中的索引類。

我有這樣的問題:在我讀過關於WCF的書中,單例實例被稱爲「可伸縮性的敵人」。我明白爲什麼這樣。有沒有更好的方法來確保客戶端獲得UserFTPConnection的查詢之間的WCF服務,而不是使用單例的同一個實例?

回答

2

其實這裏你的第一個問題是同步訪問這個靜態對象。 Dictionary<TKey, TValue>不是線程安全的,因此您必須確保只有一個線程同時訪問它。因此,您應該在lock中包含對此詞典的所有訪問權限,當然假設您有寫作方法和其他正在閱讀的方法。如果你只是在閱讀,你不需要同步。至於單身人士是可擴展性的敵人,這實在是一個誇張的陳述,沒有特定的場景就毫無意義。這實際上取決於確切的場景和實施。在你的例子中,你只顯示了一個字典=>所以我們可以說的是,你需要確保沒有線程正在從這個字典中讀取,而另一個線程正在寫入,並且在其他線程正在讀取時沒有線程正在寫入這個字典。

例如在.NET 4.0中,您可以使用ConcurrentDictionary<TKey, TValue>類,在這種情況下線程安全。

但有一件事是肯定的:雖然單身模式可能會或可能不是可擴展性的敵人,具體取決於具體實現,但單身模式是孤立單元可測試性的主要敵人。

+0

我沒有顯示代碼的其餘部分,因爲這與我的問題無關,但對字典的訪問位於「鎖定」塊內,因此可以正確同步。當我開始查找條目時,我的印象是「SortedDictionary」速度更快,這比插入或刪除條目的速度更重要。我不知道C#中的任何排序的併發字典。 – Escovado

+0

@Escovado,*排序字典*?從來沒有聽說過這樣的事情。字典是散列表,用於執行密鑰查找的設計,沒有爲這些數據結構定義每個命令或排序的概念。 –

+0

是的,SortedDictionary在這裏:http://msdn.microsoft.com/en-us/library/f7fta44c.aspx – Escovado

1

如果你打算使用單身人士,我建議還設置ConcurrencyMode ConcurrencyMode.Multiple。例如...

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

如果你不這樣做,你的WCF服務將是一個單身,但只允許一個線程在同一時間,這肯定會影響性能訪問。當然,你需要確保集合的線程安全性(如前面提到的答案)。

+0

謝謝你的提示。一次一個線程是不可接受的。我是這些服務的新手。 – Escovado

+0

順便說一句 - 你知道一個不同的(或更好的方法)來確保客戶端獲得我的UserFTPConnection類的相同實例,該請求在服務器請求之間持續存在嗎? – Escovado

相關問題