Проблемы параллелизма, возможные при использовании Сервисного набора атрибута Поведения WCF для ConcurrencyMode. Несколько и InstanceContextMode. PerCall?

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

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

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

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

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

Спасибо!

23
задан Brandon Linton 12 April 2010 в 13:37
поделиться

2 ответа

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

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

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

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

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

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

РЕДАКТИРОВАТЬ

Вы спросили

Есть ли увеличение производительности при использовании PerCall по сравнению с Single при использовании ConcurrencyMode.Single? Или верно обратное?

Вероятно, это будет зависеть от службы.

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

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

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

24
ответ дан 29 November 2019 в 02:24
поделиться

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

7
ответ дан 29 November 2019 в 02:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: