2012-04-05 51 views
1

我們有一個簡單的WCF服務,使用InstanceContextMode = Single和ConcurrencyMode = Multiple進行標記。對於返回列表的方法,我們只需返回列表的本地副本,而不是在我們的數據庫和填寫列表時填充列表。該列表由後臺線程維護,後臺線程每24小時發送到我們的數據庫並重新填充列表。我們通過在兩個地方鎖定對象來處理併發問題:在返回集合的方法內部以及在填充集合的方法內部。多線程WCF服務中高效的集合維護

我的問題是,我們如何能讓這個效率更高。目前,我們在出維修方法「GetCustomers的」瓶頸客戶端將撥打:

public List<ZGpCustomer> GetCustomers() 
{ 
    List<ZGpCustomer> customerListCopy = new List<ZGpCustomer>(); 
    lock (_customerLock) 
    { 
     customerListCopy = new List<ZGpCustomer>(_customers); 
    } 

    return customerListCopy; 
} 

由於「_customers」被填充僅每24小時,好像我們只應每一個需要裏面的鎖GetCustomers方法僅在修改集合時使用。按照當前設置的方式,如果同時發送1000個請求,我們正在有效排隊1000個請求,因爲一次只有1個線程可以訪問該方法。這使得服務的多線程方面有些無用,不是嗎?

是否有這種模式的最佳做法?我應該使用更合適的數據收集來存儲我的對象嗎? 「BlockingCollection」會更合適嗎?

+0

沒有任何證據:你可以看看System.Collections.Concurrent中的集合,我猜會比鎖更快地處理它:http://msdn.microsoft.com/de-de/ library/system.collections.concurrent.aspx – mattanja 2012-04-05 14:18:41

回答

2

確實有這樣做的更有效的方法。訣竅是保持對集合的主引用不可變。這樣你就不必在閱讀器端同步訪問。只有事物的作者一方需要鎖定。讀者一方不需要讀者保持高度併發。您唯一需要做的是將_customers參考標記爲volatile。

// Variable declaration 
object lockobj = new object(); 
volatile List<ZGpCustomer> _customers = new List<ZGpCustomer>(); 

// Writer 
lock (lockobj) 
{ 
    // Create a temporary copy. 
    var copy = new List<ZGpCustomer>(_customers); 

    // Modify the copy here. 
    copy.Add(whatever); 
    copy.Remove(whatever); 

    // Now swap out the references. 
    _customers = copy; 
} 

// Reader 
public List<ZGpCustomer> GetCustomers() 
{ 
    return new List<ZGpCustomer>(_customers); 
} 

如果你願意改變的GetCustomers簽名略微你可以利用的_customers不變性,並返回一個只讀包裝。

// Reader 
public IList<ZGpCustomer> GetCustomers() 
{ 
    return _customers.AsReadOnly(); 
} 
+0

感謝您的回覆......您能解釋一下關於您的第二條評論,關於返回客戶列表的只讀副本嗎?遵循關於只讀副本的建議,我會運行哪些風險*不* – Thelonias 2012-04-05 14:48:08

+1

我應該說* wrapper *而不是* copy *來驅動home,在'GetCustomers'中可能不需要實際的複製操作,這會進一步提高性能。 – 2012-04-05 14:57:40

+0

阿好,陷入困境。再次感謝您的信息。我從未考慮過易變的價值,所以我想是時候了! – Thelonias 2012-04-05 15:14:20