Управление Памятью Словаря C#
у меня есть Dictionary<string,int>
который может содержать более 10 миллионов уникальных ключей. Я пытаюсь уменьшить объем памяти, который это занимает, сохраняя при этом функциональность словаря.
у меня была идея сохранить хэш строки как длинный вместо этого, это уменьшает использование памяти приложений до приемлемого количества (~1.5 gig до ~.5 gig), но я не очень хорошо отношусь к своему методу для этого.
long longKey=
BitConverter.ToInt64(cryptoTransformSHA1.ComputeHash(enc.GetBytes(strKey)), 0);
в основном это котлеты с конца хэша SHA1 и помещает первый кусок в длинный, который я затем использую в качестве ключа. Хотя это работает, по крайней мере, для данных, с которыми я тестирую, я не чувствую, что это очень надежное решение из-за увеличенной возможности ключевых столкновений.
есть ли другие способы уменьшить объем памяти словаря, или метод, который я имею выше, не так ужасен, как я думаю?
[редактирование]
Чтобы уточнить, мне нужно сохранить возможность поиска a значение, содержащееся в словаре с помощью строки. Хранение фактической строки в словаре занимает много памяти. Вместо этого я хотел бы использовать Dictionary<long,int>
где long является результатом функции хэширования в строке.
6 ответов
поэтому я сделал что-то подобное недавно и по определенному набору причин, которые довольно уникальны для моего приложения, не использовал базу данных. На самом деле я пытался прекратить использовать базу данных. Я обнаружил, что GetHashCode значительно улучшен в 3.5. Одно важное замечание: никогда не храните настойчиво результаты GetHashCode. НИКОГДА. Они не гарантированы, что будут последовательны между версиями рамок.
Так что вам действительно нужно провести анализ ваших данных поскольку различные хэш-функции могут работать лучше или хуже в ваших данных. Вам также нужно учитывать скорость. Как правило, криптографические хэш-функции не должны иметь много коллизий, даже если количество хэшей переходит в миллиарды. Для вещей, которые мне нужно быть уникальными, я обычно использую SHA1 Managed. В целом CryptoAPI имеет ужасную производительность, даже если базовые хэш-функции работают хорошо.
для 64-битного хэша я в настоящее время использую Lookup3 и FNV1, которые являются 32 немного хэшей вместе. Для столкновения оба должны столкнуться, что математически невероятно, и я не видел, чтобы произошло около 100 миллионов хэшей. Вы можете найти код в открытом доступе в интернете.
все еще проводите свой собственный анализ. То, что сработало для меня, может не сработать для тебя. На самом деле внутри моего офиса разные приложения с разными требованиями фактически используют разные хэш-функции или комбинации хэш-функций.
I избегал бы любых недоказанных хэш-функций. Существует столько хэш-функций, сколько людей, которые думают, что они должны их писать. Сделайте свое исследование и тест-тест.
с 10 миллионами нечетных записей вы рассматривали возможность использования базы данных с некластеризованным индексом? Базы данных имеют гораздо больше трюков в рукаве для такого типа вещей.
хэширование, по определению и по любому алгоритму, имеет потенциал столкновений - особенно с большими объемами. В зависимости от сценария, я буду очень осторожен.
использование строк может занять место, но это надежно... если вы находитесь на 64-разрядной это не должно быть слишком большим (хотя это определенно считается "большим";- p)
кстати, криптографические хэши / хэш-функции исключительно плохи для словарей. Они большие и медленные. Решая одну проблему (размер), вы только ввели другую, более серьезную проблему: функция больше не будет равномерно распределять входные данные, тем самым уничтожая единственное самое важное свойство хорошего хэша для приближения к безударной адресации (как вы, кажется, заметили сами).
/ EDIT: как отметил Андрей,GetHashCode
is на решение для этой проблемы, так как это его предназначение. И, как в настоящем словаре, вам придется работать вокруг столкновений. Одна из лучших схем для этого -двойное хэширование. К сожалению, единственным 100% надежным способом будет фактическое хранение исходных значений. Иначе вы создали бы бесконечное сжатие, которое, как мы знаем, не может существовать.
с реализациями hashtable, с которыми я работал в прошлом, хэш приводит вас к ведру, которое часто является списком ссылок других объектов, имеющих тот же хэш. Хэши не уникальны, но они достаточно хороши, чтобы разделить ваши данные на очень управляемые списки (иногда только 2 или 3), которые вы можете искать, чтобы найти свой фактический элемент.
ключом к хорошему хэшу является не его уникальность, а его скорость и возможности распространения... вы хотите, чтобы он распространялся как можно ровнее.
просто пойти получить SQLite. Вы вряд ли победите его, и даже если вы это сделаете, это, вероятно, не будет стоить времени/усилий/сложности.
базы данных SQLite.