Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> проблема с многопоточностью. создание уникального объекта в кэше 
V
    Опции темы
dmitryk1
Дата 16.9.2015, 12:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 118
Регистрация: 10.6.2008
Где: Новосибирск

Репутация: нет
Всего: 2



В системе использую объекты в которых лежат запросы к базе.
запросов разных много и хранятся они в файлах.
Некоторые редкие, некоторые выполняются очень часто.

Для ускорения работы создал пул этих объектов и получаю их методом :
Код

        private static Dictionary<string, report> reps = new Dictionary<string, report>();

        public static report Getreport(string Id, string Path = "")
        {
            report rp;
                if (reps.ContainsKey(Id))
                {
                    rp = reps[Id];
                }
                else
                {
                    rp = new report(Id, Path);
                    reps.Add(Id, rp);
                }
            return rp;
        }


соответственно первое обращение объект кэширует, остальные используют уже имеющиеся объекты.

Основная проблема возникает с частоиспользуемыми объектами, когда одновременно в разных потоках начинают запрашиваться одинаковые объекты и тут:
Код

 reps.Add(Id, rp); 

выдаётся ошибка что ключ уже добавлен.
соответственно здесь: 
Код

  if (reps.ContainsKey(Id))

его ещё не было.
С этим можно как-то бороться? 
PM MAIL GTalk Jabber   Вверх
jsharp36
Дата 16.9.2015, 13:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



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

Dictionary не ходится для работы с разных потоков.
Наиболее простой способ починить, это обернуть в lock.

Код

        private static Dictionary<string, report> reps = new Dictionary<string, report>();

        private object syncObject = new object();
        public static report Getreport(string Id, string Path = "")
        {
            lock(syncObject)
            {
                report rp;
                if (reps.ContainsKey(Id))
                {
                    rp = reps[Id];
                }
                else
                {
                    rp = new report(Id, Path);
                    reps.Add(Id, rp);
                }
                return rp;
            }
        }


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

Код

        private static ConcurrentDictionary<string, report> reps = new ConcurrentDictionary<string, report>();

        public static report Getreport(string Id, string Path = "")
        {
                report rp;
                if (!reps.TryGetValue(Id, out rp))
                {
                    rp = new report(Id, Path);
                    resp[rp] = rp;
                }

                return rp;
        }


Тут возможно будет несколько раз создаваться репорт, пока не попадет в словарь. Если не использовать Add, а resp[rp] = rp;, то гарантированно падать не будет, если есть уже значение, то перезапишет. Вопрос только в оптимальности и можно ли два раза делать один и тот же репорт. Иногда блокировки будут хуже для производительности, иногда если часто пересекаются вызовы на одинаковые репорты, то репорты (особенно если там тяжелая в конструкторе логика).

Если надо надежно только одному потоку, то блокируйте lock-ом

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
dmitryk1
Дата 17.9.2015, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 118
Регистрация: 10.6.2008
Где: Новосибирск

Репутация: нет
Всего: 2



Спасибо, тоже уже в сторону лока смотрел. Но решил поконсультироваться. В принципе блокировки не особо страшны, поскольку отчёты добавляются в кэш только после чистки его или рестарта сервера, так что вариант более чем достаточный.

Хотел уточнить - когда я подобный код с блокировками отлаживал, при дебаге он внутрь лока заходил несколькими потоками. Или при дебаге он на локи не смотрит?
PM MAIL GTalk Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
Любитель
Mymik
mr.DUDA

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Любитель, Mymik, mr.DUDA.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Разработка под ASP.NET | Следующая тема »


 




[ Время генерации скрипта: 0.1098 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.