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, пока он не уйдет.

Другие вопросы по тегам