Возможны ли проблемы параллелизма при использовании атрибута поведения службы WCF, установленного в ConcurrencyMode.Множественный и InstanceContextMode.Значение percall?



У нас есть служба WCF, которая делает много транзакционных вызовов NHibernate. Иногда мы наблюдали тайм-ауты SQL, хотя вызовы обновляли разные строки, а таблицы были настроены на блокировку уровня строк.



После копания в логах, похоже, что разные потоки вводили одну и ту же точку в коде (наша транзакция с использованием блока), и обновление зависало на фиксации. Однако это не имело смысла, потому что мы считали, что следующий класс обслуживания атрибут заставлял уникальный поток выполнения на вызов службы:



[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]


Мы недавно изменили режим параллелизма на ConcurrencyMode.Single и пока не сталкивались с какими-либо проблемами, но ошибка была очень трудной для воспроизведения (если у кого-то есть какие-либо мысли о том, чтобы смыть такую ошибку, дайте мне знать!).



Как бы то ни было, все это подводит меня к моему вопросу: не должен ли InstanceContextMode PerCall обеспечивать потокобезопасность в Службе, даже если ConcurrencyMode имеет значение multiple? Как бы это было? возможно ли, чтобы два вызова обслуживались одним и тем же экземпляром службы?



Спасибо!

625   4  

4 ответов:

Единственный способ иметь два разных клиента WCF, то есть прокси, ссылающиеся на один и тот же экземпляр службы WCF, - это использовать InstanceContextMode=InstanceContextMode.Single. Это плохой выбор, если масштабирование является проблемой, поэтому вы хотите использовать PerCall, Если можете.

Когда вы используете PerCall, каждый вызов службы WCF получает собственный экземпляр службы WCF . Экземпляр службы не используется совместно, но это не означает, что они не используют одно и то же внутреннее хранилище (например, базу данных, память, файл и т. д.). Просто помните, PerCall позволяет каждому звоните для одновременного доступа к службе WCF.

ConcurrencyMode настройка управляет потоковой моделью самой службы. Параметр Single ограничивает выполнение всех экземпляров службы WCF в одном потоке. Таким образом, если у вас есть несколько клиентов, подключающихся одновременно, они будут выполняться только по одному на стороне службы WCF. В этом случае вы используете WCF для обеспечения синхронизации. Это сработает. прекрасно, как вы уже видели, но думайте об этом, как о том, чтобы иметь только макроуровень контроля над синхронизацией-каждый вызов службы WCF будет выполняться полностью, прежде чем следующий вызов может выполняться.

Установка ConcurrencyMode в Multiple, однако, позволит всем экземплярам службы WCF выполняться одновременно. В этом случае Вы несете ответственность за обеспечение необходимой синхронизации. Думайте об этом, как о микроуровне контроля над синхронизацией, так как вы можете синхронизировать только те части каждого вызова, которые необходимо синхронизировать.

Я надеюсь, что объяснил это достаточно хорошо, но вот фрагмент документации MSDN для ConcurrencyMode на всякий случай:

Установка ConcurrencyMode в Single указывает системе на ограничение экземпляры службы для одного потока исполнения в то время, которое освобождает вы от работы с потоками проблемы. Значение кратно означает, что сервисные объекты могут быть выполнены с помощью несколько потоков в любой из них время. В в этом случае вы должны обеспечить поток безопасность.

EDIT

Вы спросили

Есть ли какое-либо увеличение производительности, тогда, используя PerCall против Single при использовании ConcurrencyMode.Одинок? Или верно обратное?

Это, скорее всего, будет зависеть от сервиса.

С помощью InstanceContextMode.PerCall создается новый экземпляр службы для каждого вызова через прокси-сервер, так что у вас есть накладные расходы на создание экземпляра. Предполагая, что ваш конструктор службы не делает много, это не будет проблемой.

С помощью InstanceContextMode.Single существует только один экземпляр службы в течение всего времени существования приложения, поэтому практически нет накладных расходов, связанных с созданием экземпляра. Однако этот режим позволяет только одному экземпляру службы обрабатывать каждый вызов, который когда-либо будет выполнен. Таким образом, если у вас есть несколько вызовов, выполняемых одновременно, каждый вызов должен будет ждать завершения других вызовов, прежде чем он может быть выполнен.

Для чего это стоит того, вот как я это сделал. Используйте контекст экземпляра PerCall с параллелизмом Multiple. Внутри класса службы WCF создайте статические члены для управления внутренним хранилищем данных и при необходимости синхронизируйте доступ к этим статическим членам с помощью оператора lock, полей volatile и т. д. Это позволяет вашей службе хорошо масштабироваться, сохраняя при этом безопасность потока.

Я полагаю, что ответ заключается в том, что существует несколько потоков (на стороне клиента), использующих один и тот же экземпляр прокси, что потенциально позволяет выполнять несколько вызовов в один и тот же экземпляр. Это сообщение имеет более подробное объяснение.

InstanceContextMode.PerCall и ConcurrencyMode.Single должно быть нормально, если вы не используете двухсторонние обратные вызовы на сервере. В этом случае вам нужно будет использовать ConcurrencyMode.Reentrant, иначе обратный вызов не сможет получить доступ к заблокированному экземпляру службы и произойдет взаимоблокировка.

Так как это создание экземпляра службы per call, другие потоки или вызовы не могут получить к нему доступ. Как указано в статье, упомянутой в других ответах Статья такая комбинация все еще может быть проблемой, если сессия создается на уровне привязки И вы используете тот же объект прокси-службы.

Поэтому, если вы не используете один и тот же прокси-объект или не имеете сессионной привязки и не используете двухсторонние обратные вызовы клиенту ( скорее всего, они должны быть односторонними в любом случае) InstanceContextMode.PerCall и ConcurrencyMode.Single должны быть хорошими.

Я думаю, что все зависит от требования. Если мы собираемся звонить в одну и ту же службу так много раз, то лучше мы можем использовать InstanceContextMode-один, а concurrencymode-несколько.

Comments

    Ничего не найдено.