C # Task Parallel Library и NHibernate / Spring.NET - PullRequest
6 голосов
/ 07 января 2011

Я использую Spring.NET и NHibernate уже несколько лет, и я очень доволен.Тем не менее, я всегда играл с многопоточностью, Reactive Extensions и в конечном итоге Task Parallel Library, которая является отличным фреймворком.К сожалению, все виды многопоточных подходов терпят неудачу из-за сеанса NHiberntate, который не является потокобезопасным.

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

Например: у меня естьCustomerRegistrationService класс, метод которого Register выполняет несколько задач:

ICustumer customer = this.CreateCustomerAndAdresses(params);
this.CreateMembership(customer);
this.CreateGeoLookups(customer.Address);
this.SendWelcomeMail(customer);

Последние два метода были бы идеальными кандидатами для параллельной работы, CreateGeoLookups вызывает некоторые веб-службы для определения географического местоположения адреса клиентаи создает некоторые новые объекты, а также обновляет самого клиента.SendWelcomMail делает то, что говорит.

Поскольку CreateGeoLookups использует NHibernate (хотя через объекты репозитория, поэтому NHibernate скрыто через Interfaces / Dependency Inection), он не будет работать с Task.Factory.StarNew (...) или другие механизмы Threading.

Мой вопрос не в том, чтобы решить эту самую проблему, которую я описал, но я хотел бы услышать от вас информацию о NHibenrate, Spring.NET и параллельных подходах.

Большое спасибо Макс

Ответы [ 3 ]

8 голосов
/ 08 января 2011

В NH ISession не является поточно-ориентированным, но ISessionFactory полностью поточно-ориентирован, легко поддерживает то, что вам нужно.Если вы спроектировали управление сессионным жизненным циклом (и зависящие от него репозитории) таким образом, что вы предполагаете одну единую сессию IS между вызовами, то да, у вас будут проблемы такого рода.Но если вы разработали свой шаблон обработки сеанса так, чтобы он предполагал только одну ISessionFactory, но не делал предположений относительно ISession, то ничто по своей сути не мешает вам взаимодействовать с NH параллельно.

Хотя вы специально этого не делаетеупомяните ваш вариант использования как веб-, важно отметить, что в веб-ориентированных случаях (например, что является довольно распространенным случаем для пользователей Spring.NET, а также многих других платформ управления NH),часто используемый шаблон управления сеансом «Session-Per-Request» (часто называемый в Spring.NET «Open Session In View» или просто «OSIV») НЕ будет работать, и вам нужно будет переключиться на другую продолжительностьЖизненный цикл ISession.Это связано с тем, что (как следует из названия) шаблон сессия-на-запрос / OSIV делает (теперь неверно в вашем случае) предположение, что существует только один экземпляр ISession для продолжительности каждого запроса HttpRequest (и, вероятно, вы захотите бытьпорождая эти параллельные вызовы NH в контексте одного HttpRequest в случае использования в Интернете).

Очевидно, что в случае, не связанном с сетью, редко встречается концепция, аналогичная сеансу на запрос, вы не будетевероятность возникновения этой проблемы настолько же высока, насколько и управление жизненным циклом сеанса редко бывает таким мелкозернистым / недолговечным, как в веб-приложениях.

Надеюсь, это поможет.

-Steve B.

2 голосов
/ 07 ноября 2011

Это сложная вещь, которую вы просите. К DTC следует обращаться с осторожностью.

Единственное решение, которое я могу знать, это использование надежного транзакционного обмена сообщениями (например, MSMQ + NServiceBus / MassTransit).

Такой дизайн позволяет вам сделать это. Это будет выглядеть так:

var customerUid=CreateCustomers(); 
Bus.Publish(new CustomerCreatedEvent() { CustomerUid = customerUid});

Тогда вы можете использовать два обработчика событий (Reactors), которые обрабатывают событие и отправляют EMail или создают запросы.

Это также не позволит вам делиться Транзакцией, но обеспечит запуск Реакторов (в новой Транзакции), когда создание клиента завершится успешно. Также это не имеет ничего общего с TPL.

0 голосов
/ 10 января 2011

Ну, спасибо, что ответили.Я знаю, что «ISession не является поточно-ориентированным, но ISessionFactory является полностью поточно-ориентированным».Например, моя проблема в приведенном выше коде заключается в том, что вся операция заключена в одну транзакцию.Поэтому this.CreateCustomerAndAdresses (params) в основном потоке # 1 будет использовать, например, ISession # 1 с транзакцией # 1.Вызов трех других параллельно создаст еще три потока и еще три сеанса и транзакции, что приведет к тайм-ауту базы данных в моем случае.Я предполагаю, что транзакция № 1 не была успешно зафиксирована, поскольку она ожидает завершения трех одновременных задач.Но три одновременные задачи пытаются прочитать из базы данных, пока транзакция все еще активна, что приводит к тупикам / тайм-аутам.

Так что есть какой-то способ сказать другим потокам / сеансам не создавать новую транзакцию, а использоватьОсновная транзакция # 1?

Я использую TxScopeTransactionManager из Spring.NET, который использует DTC (System.Transactions).Я догадался, что, возможно, System.Transactions.DependentTransaction мог бы работать, но не имею понятия, как интегрировать его в мой сценарий управления транзакциями Spring.NET.

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...