2016-03-01 3 views
1

Во-первых, я не очень разбираюсь в многопоточном и параллельном программировании.Parallel.ForEach используется с NHibernate, что приводит к блокировкам SQL Server

Я пытаюсь оптимизировать работу устаревшего приложения (.Net 4, NHibernate 2.1).

** До сих пор обновление NHibernate не является приоритетом, но находится в стадии разработки.

Со временем производительность стала кошмаром с ростом данных. Один элемент, который я видел, - это оператор Parallel.ForEach, который вызывает метод, который извлекает и обновляет сложную сущность (с несколькими отношениями - пропозиции &).

Кусок кода имеет следующий форма (упрощенный для ясности):

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»)

Есть ли лучший способ справиться с это параллельно, или я должен реорганизовать код в традиционный цикл?

Я знаю, что я могу в качестве альтернативы реализовать свой код с помощью:

  1. foreach петли в том же ISession контексте
  2. С сессионного
  3. С Environment.BatchSize набором разумного значением

OR

  1. Использование SQL BulkCopy

Я также прочитал совсем немного хорошей информации о тупиков SQL Server и Parallel.ForEach будучи простой ловушкой:

  1. SQL Transaction was deadlocked
  2. Using SQL Bulk Copy as an alternative
  3. Potential Pitfalls in Data and Task Parallelism
  4. Multi threading C# application with SQL Server database calls

ответ

1

Это очень сложная тема.Есть одна стратегия, которая гарантированно будет безопасной, и возможно приведет к ускорению:

Повторите попытку в случае тупика.

Поскольку тупик отменяет транзакцию, вы можете спокойно повторить всю транзакцию. Если скорость тупика низкая, ускорение параллелизма будет высоким.

Приятная вещь о повторении заключается в том, что вы можете сделать простое изменение кода в центральном месте.

Поскольку это не очевидно из отправленного кода: убедитесь, что потоки не разделяют сеанс или сущности. Ни один из них не является потокобезопасным.

+0

Спасибо за ваш вклад. Это действительно сложно, и возможные решения многоцелевы. Попробуете свою стратегию Retry. Другая сложность, которая добавляет больше гаечных ключей к работам, - это несколько «SELECTS» и «UPDATES», которые происходят для некоторых объектов из-за стратегии генерации ключей NHibernate. В потоках нет общего доступа к одному сеансу, как я уже говорил – user919426

+0

Генерация ключей hilo должна выполняться в отдельной транзакции, если NHibernate делает это правильно. В этом не должно быть взаимоблокировок. Вы можете проверить это с помощью SQL Profiler. – usr

Смежные вопросы