首先,我不是多線程和並行編程方面的專家。Parallel.ForEach與NHibernate一起使用導致SQL Server鎖
我正試圖優化遺留應用程序的性能(.Net 4
,NHibernate 2.1
)。
**到目前爲止,升級NHibernate
不是優先事項,但正在籌備中。
隨着時間的推移,性能已成爲數據增長的噩夢。我看到的一個項目是Parallel.ForEach
語句,它調用一個方法來獲取和更新一個複雜的實體(具有多個關係 - propeties &集合)。
的一段代碼具有以下形式(爲了清楚而簡化):
void SomeMethod(ICollection<TheClass> itemsToProcess)
{
Parallel.ForEach(itemsToProcess, item => ProcessItem(item);
}
TheClass ProcessItem(TheClass i)
{
var temp = NHibernateRepository.SomeFetchMethod(i);
var result = NHibernateRepository.Update(temp);
return result;
}
SQL Server的間歇報告數據庫鎖定錯誤,錯誤如下:
Transaction (Process ID 20) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction
我懷疑這是由於一些競爭狀態導致死鎖,即使ISessions
是分開的。
的ICollection<TheClass>
最多可以有1000項和每個屬性和處理後的子集,產生許多SELECT
和UPDATE
語句(使用「NHibernate的探查器」確認)
有沒有更好的方式來處理這是以平行的方式,還是我應該重構代碼到傳統的循環?
我知道,我可以用替換地實現我的代碼:
- 一個
foreach
循環在同一ISession
背景 - 和一個無狀態會話
- 隨着
Environment.BatchSize
設置爲一個合理的值
或
- 使用SQL BulkCopy
我也看過不少關於SQL服務器死鎖好的信息和Parallel.ForEach
是一件容易的陷阱:
- SQL Transaction was deadlocked
- Using SQL Bulk Copy as an alternative
- Potential Pitfalls in Data and Task Parallelism
- Multi threading C# application with SQL Server database calls
感謝您的輸入。確實很複雜,可能的解決方案是多方面的。將嘗試您的重試策略。另一個增加更多扳手的複雜性是由於'NHibernate'密鑰生成策略導致的一些實體發生的多重'SELECTS'和'UPDATES'。正如我提到 – user919426
hilo密鑰生成應該發生在一個單獨的事務中,如果NHibernate正確地執行它。不應該有涉及這個的僵局。你可以使用SQL Profiler來檢查。 – usr