Подтвердить что ты не робот

Должен ли я использовать словарь С#, если мне нужен только быстрый поиск ключей, а значения неактуальны?

Мне нужен тип данных, который может вставлять записи, а затем иметь возможность быстро определить, была ли запись уже вставлена. Кажется, что A Dictionary соответствует этой потребности (см. Пример). Однако я не использую словарь values. Должен ли я использовать словарь или есть еще один подходящий тип данных?

public class Foo
{
    private Dictionary<string, bool> Entities;

    ...

    public void AddEntity(string bar)
    {
        if (!Entities.ContainsKey(bar))
        {
            // bool value true here has no use and is just a placeholder
            Entities.Add(bar, true);
        }
    }

    public string[] GetEntities()
    {
        return Entities.Keys.ToArray();
    }

}
4b9b3361

Ответ 1

Вы можете использовать HashSet<T>.

Класс HashSet<T> обеспечивает высокопроизводительные операции набора. Множество представляет собой набор, содержащий не дублирующие элементы и элементы не имеют особого порядка.

Ответ 2

Ответ Habib отлично, но для многопоточных сред, если вы используете HashSet<T>, то по последнему слову вам нужно использовать lock для защиты доступа к нему, Я нахожу себя более склонным к созданию тупиков с операторами lock. Кроме того, lock дает худшее ускорение в закон Amdahl, потому что добавление оператора lock уменьшает процент вашего кода, который фактически параллелен.

По этим причинам ConcurrentDictionary<T,object> соответствует счету в многопоточных средах. Если вы закончите использовать его, оберните его, как в своем вопросе. Просто new вверх object, чтобы подбрасывать как значения по мере необходимости, так как значения не будут важны. Вы можете убедиться, что в исходный код нет операторов lock.

Если вам не нужна переменчивость коллекции, то это будет спорным вопросом. Но ваш вопрос подразумевает, что вам это нужно, поскольку у вас есть метод AddEntity.

Дополнительная информация 2017-05-19. Фактически, ConcurrentDictionary использует внутренние блокировки, хотя и не lock для операторов - использует Monitor.Enter (проверьте TryAddInternal). Тем не менее, он, кажется, блокирует отдельные ведра в словаре, а это означает, что будет меньше споров, чем положить все в инструкцию lock.

В общем, ConcurrentDictionary часто лучше подходит для многопоточных сред.

На самом деле довольно сложно (невозможно?) сделать параллельный хеш-набор, используя только методы Interlocked. Я пробовал самостоятельно и постоянно сталкивался с проблемой необходимости одновременного изменения двух вещей - что-то, что может делать только блокировка в целом. Одним из обходных решений, которые я нашел, было использование односвязных списков для хэш-ковшей и преднамеренное создание циклов в списке, когда один поток должен был работать на node без помех от других потоков; это приведет к тому, что другие потоки будут пойманы, вращаясь в одном и том же месте, пока эта нить не будет выполнена с помощью node и не уменьшит цикл. Конечно, он технически не использовал блокировки, но он плохо масштабировался.