首先,我不是多线程和并行编程方面的专家。
我正在尝试优化遗留应用程序(.Net 4
,NHibernate 2.1
)的性能。
**到目前为止,升级NHibernate
不是优先事项,而是正在筹备中。
随着时间的推移,随着数据的增长,性能已成为一场噩梦。我看到的一个项目是一个Parallel.ForEach
语句,它调用一个方法来获取和更新一个复杂的实体(具有多个关系 - propeties& collections)。
这段代码具有以下形式(为简洁起见而简化):
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 Profiler'确认)< / p>
是否有更好的方法以并行方式处理此问题,还是应该将代码重构为传统循环?
我知道我可以使用以下方式实现我的代码:
foreach
上下文ISession
循环
Environment.BatchSize
设置为合理的值OR
我还阅读了很多关于SQL Server死锁的信息,Parallel.ForEach
很容易陷入困境:
答案 0 :(得分:1)
这是一个非常复杂的话题。有一种策略可以保证安全,可能会导致加速:
在发生死锁时重试。
由于死锁回滚事务,您可以安全地重试整个事务。如果死锁率很低,并行性加速会很高。
重试的好处是你可以在一个中心位置进行简单的代码更改。
由于发布的代码不明显:确保线程不共享会话或实体。它们都不是线程安全的。