![](/img/trans.png)
[英]WCF service with ConcurrencyMode.Multiple and InstanceContextMode.Single behavior and multithreading safety
[英]Are concurrency issues possible when using the WCF Service Behavior attribute set to ConcurrencyMode.Multiple and InstanceContextMode.PerCall?
我們有一個WCF服務,可以進行大量的事務NHibernate調用。 偶爾我們看到SQL超時,即使調用更新了不同的行,並且表被設置為行級鎖定。
在深入研究日志之后,看起來不同的線程正在進入代碼中的相同點(我們的事務使用塊),並且更新掛起在提交上。 但是,它沒有意義,因為我們認為以下服務類屬性強制每個服務調用一個唯一的執行線程:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
我們最近將並發模式更改為ConcurrencyMode.Single
並且還沒有遇到任何問題,但是這個錯誤很難重現(如果有人想要刷出這樣的錯誤,請告訴我!)。
無論如何,這一切都讓我想到了問題:PerCall的InstanceContextMode是否應該在服務中強制執行線程安全,即使ConcurrencyMode設置為多個? 如何通過同一個服務實例為兩個調用提供服務?
謝謝!
擁有兩個不同的WCF客戶端(即代理)引用WCF服務的同一實例的唯一方法是使用InstanceContextMode=InstanceContextMode.Single
。 如果縮放是一個問題,這是一個糟糕的選擇,所以如果可以,你想要使用PerCall
。
使用PerCall
, WCF服務的每個CALL都會獲得自己的WCF服務實例 。 沒有共享服務實例,但這並不意味着它們不共享相同的后端存儲(例如,數據庫,內存,文件等)。 請記住, PerCall
允許每個調用同時訪問您的WCF服務。
ConcurrencyMode
設置控制服務本身的線程模型。 設置為Single
將所有WCF服務實例限制為在同一線程上運行。 因此,如果您同時連接多個客戶端,則它們將僅在WCF服務端一次執行一個。 在這種情況下,您可以利用WCF提供同步。 正如您所見,它會正常工作,但我認為這只是對同步的宏級控制 - 每個WCF服務調用將在下一次調用執行之前完整執行。
但是,將ConcurrencyMode
設置為Multiple
將允許所有WCF服務實例同時執行。 在這種情況下, 您負責提供必要的同步 。 可以將其視為對同步進行微級控制,因為您只能同步每個需要同步的調用的那些部分。
我希望我已經很好地解釋了這一點,但這里是ConcurrencyMode
的MSDN文檔的片段,以防萬一:
將ConcurrencyMode設置為Single指示系統一次將服務實例限制為一個執行線程,這使您無需處理線程問題。 值Multiple表示服務對象可以在任何時候由多個線程執行。 在這種情況下,您必須確保線程安全。
編輯
您詢問
那么,在使用ConcurrencyMode.Single時,使用PerCall與Single是否有任何性能提升? 或者是反過來的?
這可能取決於服務。
使用InstanceContextMode.PerCall
,將通過代理為每個調用創建一個新的服務實例,因此您需要處理實例創建的開銷。 假設您的服務構造函數沒有做太多,這不會是一個問題。
使用InstanceContextMode.Single
,在應用程序的生命周期中只存在一個服務實例,因此實際上沒有與實例創建相關的開銷。 但是,此模式僅允許一個服務實例處理將要進行的每個調用。 因此,如果您同時進行多個呼叫,則每個呼叫都必須等待其他呼叫完成才能執行。
對於它的價值,這就是我如何做到這一點。 將PerCall
實例上下文與Multiple
並發一起使用。 在WCF服務類中,創建靜態成員以管理后端數據存儲,然后根據需要使用lock
語句, volatile
字段等同步對這些靜態成員的訪問。這使您的服務可以在保持良好的同時進行維護線程安全。
我相信答案是有多個線程(在客戶端)使用相同的代理實例,因此可能允許多個調用進入同一個實例。 這篇文章有更詳細的解釋。
如果您不在服務器上使用雙向回調, InstanceContextMode.PerCall
和ConcurrencyMode.Single
應該沒問題。 在這種情況下,您將需要使用ConcurrencyMode.Reentrant
或回調將無法訪問鎖定的服務實例,並且將發生死鎖。
由於每次調用服務實例創建,因此其他線程或調用無法訪問它。 正如在其他的答案中提到的文章指出文章這樣的組合仍然是一個問題,如果會話在結合水平creatd並且正在使用相同的服務代理對象。
因此,如果您不使用相同的代理對象或沒有會話綁定,並且不使用雙向回調到客戶端(最有可能它們應該是OneWay) InstanceContextMode.PerCall
和ConcurrencyMode.Single
應該是好的。
我認為這完全取決於要求。 如果我們要多次調用相同的服務,那么我們可以使用InstanceContextMode是Single,並且concurrencymode是多個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.