Методы WCF совместно используют словарь

#c# #.net #wcf #web-services #thread-safety

#c# #.net #wcf #веб-службы #безопасность потоков

Вопрос:

Я создаю библиотеку служб WCF, и у меня есть вопрос относительно безопасности потоков, использующих метод внутри этой библиотеки, вот полная реализация, которая у меня есть до сих пор.

 namespace WCFConfiguration
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
    public class ConfigurationService : IConfigurationService
    {
        ConcurrentDictionary<Tuple<string,string>, string> configurationDictionary = new ConcurrentDictionary<Tuple<string,string>, string>();

        public void Configuration(IEnumerable<Configuration> configurationSet)
        {
            Tuple<string, string> lookupStrings;
            foreach (var config in configurationSet)
            {
                lookupStrings = new Tuple<string, string>(config.BoxType, config.Size);
                configurationDictionary.TryAdd(lookupStrings, config.RowNumber);
            }
        }

        public void ScanReceived(string boxType, string size, string packerId = null)
        {

        }
    }
}
  

Представьте, что у меня есть 10 значений в моем configurationDictionary, и многие люди хотят запросить этот метод ScanReceived, использующий словарь, являются ли эти 10 значений общими для каждого из клиентов, которые запрашивают ScanReceived? Нужно ли мне менять свое поведение в отношении обслуживания?

Кстати, метод настройки используется только одним человеком.

Комментарии:

1. Ваша служба имеет режим ConcurrencyMode. Одиночный, поэтому у вас не возникнет проблем с параллелизмом. Кроме того, ScanReceived не имеет кода, поэтому я уверен, что вы будете в безопасности, вызывая метод no-op, возвращающий void.

2. Я все еще работаю над кодом ScanReceived, но он изменится на int.

Ответ №1:

С InstanceContextMode помощью of PerCall вы должны получать новый экземпляр вашей службы и вашего словаря каждый раз, когда поступает удаленный вызов (который, я предполагаю, будет либо Configuration() или ScanReceived() ). Это не будет использоваться configurationDictionary несколькими клиентами.

С помощью a ConcurrencyMode of Single у вас будет только один поток, выполняющий ваш код одновременно. Таким образом, любые проблемы параллелизма являются спорными.

Два способа совместного использования configurationDictionary :

  1. Сделайте его статическим: private readonly static ConcurrentDictionary<...> ...
  2. Измените свой InstanceContextMode и, возможно, ваш ConcurrencyMode .

Я бы рекомендовал первый вариант, если вы не ожидаете тысяч обращений к вашей службе в секунду.

В MSDN есть некоторая информация о InstanceContextMode и создании экземпляров классов служб.


Если вы измените на InstanceContextMode.Single и ConcurrencyMode.Multiple , вы можете получить много потоков, выполняющихся одновременно, и вам нужно будет беспокоиться о синхронизированном доступе.

Главное, на что следует обратить внимание, это то, что когда вы запрашиваете / перебираете свой словарь, кто-то другой может его изменить. Получение моментального снимка словаря и затем запрос моментального снимка должны решить эту проблему:

 foreach (var x in configurationDictionary.ToArray())
{
     ....
}
  

Или, если вы используете LINQ:

 var someResult = configurationDictionary.ToArray().Where(...).Select(...)
  

Комментарии:

1. Я не знаю, сколько вызовов я собираюсь получить, но я почти уверен, что это будет сделано в порядке, мне рекомендовали сделать для этого синглтон, но я не знаю, хороший ли это подход.

2. что, если я установлю свойство следующим образом: [ServiceBehavior(InstanceContextMode = InstanceContextMode. Одиночный, ConcurrencyMode = ConcurrencyMode. Одиночный)] ??

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

4. Итак, короче говоря, оба одиночных будут в порядке для ваших целей, если у вас всего несколько клиентов.

5. Я не знаю, стоит ли упоминать об этом, но метод ScanRecieved будет отправлять строку по TCP-соединению на принтер обрабатываемого устройства, поэтому мне нужно было быть в последовательности.