Одночасний словник Правильне використання


84

Чи правильно я вважаю, що це правильне використання одночасного словника

private ConcurrentDictionary<int,long> myDic = new ConcurrentDictionary<int,long>();

//Main thread at program startup

for(int i = 0; i < 4; i++)
{
  myDic.Add(i, 0);
}

//Seperate threads use this to update a value

myDic[InputID] = newLongValue;

У мене немає блокувань тощо, і я просто оновлюю значення в словнику, хоча кілька потоків намагаються зробити те саме.


2
Це залежить - чи newLongValueзалежить від попереднього значення myDic[InputID]?
Damien_The_Unbeliever

3
вам слід уникати доступу за допомогою ключа безпосередньо myDic[InputID]для стану перегони. СпробуйтеGetOrAdd
Олів'є Альбертіні

3
@OlivierAlbertini, я не думаю, що myDic[InputID]викликає будь-які проблеми, коли його використовують як значення. GetOrAddне є правильною заміною, оскільки додає лише в тому випадку, якщо значення не існує. Натомість ми можемо використовувати AddOrUpdateдля додавання / оновлення того самого значення у словнику.
Jatin Sanghvi

Відповіді:


75

Це залежить від того, що ви маєте на увазі під захистом від потоків.

З MSDN - Як: Додавати та видаляти елементи з ConcurrentD Dictionary :

ConcurrentDictionary<TKey, TValue>призначений для багатопотокових сценаріїв. Вам не потрібно використовувати замки в коді, щоб додавати або видаляти елементи з колекції. Однак завжди можна для одного потоку отримати значення, а іншому - негайно оновити колекцію, надавши цьому ж ключу нове значення.

Отже, можна отримати суперечливий погляд на вартість елемента у словнику.


2
Це цікавий момент! Ви все-таки застосуєте замок у такому випадку?
Джон

@Jon - Це залежить від вашої програми та від того, чи все в порядку. Але я б сказав, що якщо ви хочете мати послідовний перегляд елементів, вам потрібно буде обернути кожне прочитане та оновити елемент у замку.
Оді

12
Я думаю, що це не те, що сказано в документі. Невідповідність пов’язана з тим, що містить подання, якщо подання є лише значенням, то воно цілком узгоджується. Поки ви отримуєте значення ключа, значення ключа в словнику може змінюватися. Це так само непослідовно, як значення DateTime.Now.
Джордж Мавріцакіс

4

Найкращий спосіб дізнатися це - перевірити документацію MSDN.

Сторінка для ConcurrentDictionary - http://msdn.microsoft.com/en-us/library/dd287191.aspx

У розділі безпеки потоків зазначено: "Усі загальнодоступні та захищені члени ConcurrentDictionary (Of TKey, TValue) є потокобезпечними та можуть використовуватися одночасно з декількох потоків."

Отже, з точки зору паралелізму з вами все гаразд.


2

Так, ти правий.

Це і можливість перерахувати словник в одному потоці, змінюючи його в іншому, є єдиним засобом існування для цього класу.


9
Я б хотів додати, що тут є корисна інформація про те, як і коли використовувати ConcurrentDictionary.
alex.b

1

Це залежить, у моєму випадку я віддаю перевагу використанню цього методу.

ConcurrentDictionary<TKey, TValue>.AddOrUpdate Method (TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>);

Детальні відомості про використання методу див. У бібліотеці MSDN .

Зразок використання:

results.AddOrUpdate(
  Id,
  id => new DbResult() {
     Id = id,
     Value = row.Value,
     Rank = 1
  },
  (id, v) =>
  {
     v.Rank++;
     return v;
  });

2
FYI: "Коли ви надаєте метод фабрики значень (до методів GetOrAdd та AddOrUpdate), він може фактично запуститись, а його результат буде відкинутий згодом (оскільки якийсь інший потік виграв гонку)." Більше інформації тут: arbel.net/2013/02/03/…
keremispirli

Так, ви маєте рацію, як зазначено у розділі зауважень "Якщо ви одночасно викликаєте AddOrUpdate у різних потоках, addValueFactory може викликатися кілька разів, але її пара ключ / значення може не додаватися до словника для кожного виклику." Тому вам слід бути впевненим, що ви не генеруєте кілька постійних об’єктів.
Онур,

І якщо вам потрібно оновити вміст, не змінюючи повністю збережений об'єкт, наприклад, щоб змінити властивість раніше доданого об'єкта, цей метод корисний, інакше потрібно використовувати блокування або інші методи синхронізації.
Онур,

1

Тільки примітка: Не виправдовує використання об’єкта ConcurrentDicitonary з лінійним циклом, що робить його недостатньо використаним. Найкраща альтернатива - дотримуватися рекомендацій Документації Microsoft, як згадано Одедом, використовуючи паралелізм, згідно з прикладом нижче:

Parallel.For(0, 4, i => 
{
   myDic.TryAdd(i, 0);
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.