C# - блокировка приращения по словарю как список
Я знаю, что int не будет иметь фиксированной позиции в памяти, поэтому он просто не может так работать. Но точно такая же часть кода будет выполняться одновременно с разными именами, параметрами и т. Д.
Мне нужно по существу передать строку "Имя", а затем каким-то образом увеличить один из элементов в моем массиве int.
Dictionary<string, int> intStats = new Dictionary<string, int>();
В этом словаре хранятся все статистические данные, основанные на имени, указанном в качестве строкового ключа словарей.
И так как я использую много многопоточности, я хочу, чтобы подсчет int был максимально синхронизирован. Вот почему я пытаюсь использовать Interlocked.Increment(ref intStats[theName]);
Но, к сожалению, это не сработает.
Есть ли альтернативы, которые будут работать для моей ситуации?
1 ответ
Во-первых, я предлагаю создать пользовательский тип, который фиксирует семантику вашего абстрактного типа данных. Таким образом, вы можете экспериментировать с различными реализациями, и таким образом ваши сайты вызовов становятся самодокументирующимися.
internal sealed class NameCounter
{
public int GetCount(string Name) { ... }
public void Increment(string Name) { ... }
}
Итак: какие варианты реализации вы можете сделать, учитывая, что это должно быть потокобезопасным?
личное
Dictionary<string, int>
будет работать, но вам придется блокировать словарь при каждом доступе, что может дорого обойтись.личное
ConcurrentDictionary<string, int>
, но имейте в виду, что вы должны использоватьTryUpdate
в цикле, чтобы убедиться, что вы не потеряете значения.сделать тип обёртки:
internal sealed class MutableInt
{
public int Value;
}
Это один из редких случаев, когда вы хотите сделать публичное поле. Теперь сделайте ConcurrentDictionary<string, MutableInt>
, а потом InterlockedIncrement
публичное поле. Теперь вам не нужно TryUpdate
, но здесь все еще есть гонка: если два потока одновременно пытаются в одно и то же время добавить одно и то же имя, то вы должны убедиться, что победит только один из них. использование AddOrUpdate
тщательно, чтобы эта гонка не состоялась.
Реализуйте свой собственный параллельный словарь в виде хеш-таблицы, которая индексирует в массив int;
InterlockedIncrement
на элементах массива. Опять же, вам нужно быть предельно осторожным, когда в систему вводится новое имя, чтобы гарантировать, что коллизии хешей обнаруживаются поточно-ориентированным способом.Хешируйте строку в одно из n сегментов, но на этот раз эти сегменты являются неизменяемыми словарями. Каждое ведро имеет замок; заблокировать ведро, создать новый словарь из старого, положить его обратно в ведро, разблокировать ведро. Если есть раздор, увеличивайте n, пока он не уйдет.