какой лучший идентификатор при кэшировании наборов? Когда происходит вычисление hashCode набора?

Как лучше всего реализовать кеш для наборов? В частности, что лучше всего подходит для кеша?

В статический фабричный метод я хочу включить механизм кэширования, чтобы можно было повторно использовать существующие (неизменяемые) объекты. Такое повторное использование не должно приводить к значительному снижению производительности. Критические данные этого класса — это параметризованный LinkedHashSet. Мне интересно, разумно ли использовать хэш-код этого набора в качестве ключа для кеша (HashMap), потому что в документации по java говорится: «Хэш-код набора определяется как сумма хэш-кодов элементы множества». Разве это не потенциально медленный процесс? Когда он рассчитывается? Как только Set генерируется или по запросу? Не может ли это на самом деле съесть много прироста производительности, который я ожидаю получить за счет кэширования?

Кроме того, hashCode — это int, но HashMaps не принимает примитивы, так что это требует упаковки в Integer, верно?

Мой текущий подход состоял бы в том, чтобы поддерживать дополнительный набор длин наборов существующих объектов. Фабричный метод сначала проверяет, указана ли длина текущего набора, и только затем ищет в фактическом индексе. Но это касается и бокса...

Есть ли лучшее решение?


person ib84    schedule 07.07.2011    source источник
comment
hashCode для набора зависит от его содержимого. Для кеша у вас обычно есть ключ, который идентифицирует данные, которые представляет набор (например, admin-memberid), а содержимое (и хэш-код) может меняться со временем.   -  person Thilo    schedule 07.07.2011
comment
спасибо тило. Предполагая, что набор ключей является окончательным и не меняется, тогда хэш-код набора - мой единственный разумный выбор для определения набора, верно?   -  person ib84    schedule 07.07.2011
comment
Вы можете использовать сам набор в качестве ключа (это позволяет избежать коллизий).   -  person Paŭlo Ebermann    schedule 07.07.2011
comment
@paulo: что произойдет под капотом, если я использую набор в качестве ключа? разве это не спасет единственную ссылку из этого набора? Если бы я искал семантически идентичный другой набор, совпал бы кеш или нет? Не уверен, но думаю, что не будет   -  person ib84    schedule 07.07.2011
comment
Если вы используете сам Set в качестве ключа, то кеш будет практически бесполезен (вам нужны данные, которые вы хотите получить из кеша, чтобы использовать кеш).   -  person Thilo    schedule 08.07.2011


Ответы (2)


Вам нужно использовать какой-то инвариант в качестве ключа для каждого набора, что-то, что логически определяет содержимое этого набора.

Подумайте о том, чтобы создать NamedSet, либо обернув существующую реализацию набора простым делегатом, либо подклассировав его (если он не является окончательным). Затем вы можете указать дополнительный ключ или поле имени, чтобы идентифицировать набор и использовать его в качестве ключа для вашего кеша.

person Joel    schedule 07.07.2011
comment
Спасибо за ответ. в моих наборах сложно найти инвариант, так как они состоят из наборов ключей/ручек, которые очень часто могут частично перекрываться. Кстати, я искал в stackoverflow, google и wiki, но я мог найти, что именно вы подразумеваете под NamedSet. Не могли бы вы объяснить? - person ib84; 07.07.2011
comment
NamedSet — это просто то, что я придумал :-), так что вы можете сказать mySet.getType() или mySet.getName(), предполагая, что существует какое-то общее отношение, описывающее элементы в наборе. - person Joel; 07.07.2011
comment
ах! Хорошо, я вижу. Да, возможно, это действительно вариант, так как набор ключей является результатом какого-то запроса. Возможно, каким-то образом я мог бы использовать запрос в качестве ключа... конечно... спасибо! - person ib84; 07.07.2011

Разве это не потенциально медленный процесс? Когда он рассчитывается? Как только Set генерируется или по запросу? Не может ли это на самом деле съесть много прироста производительности, который я ожидаю получить за счет кэширования?

В принципе, это не указано в интерфейсе Set, поэтому зависит от реализации.

Для реализаций наборов общего назначения в java.util и java.util.concurrent (а также для представлений наборов карт общего назначения) hashCode() вычисляется по запросу и для больших наборов будет медленным. (Для небольших наборов с простыми элементами это не имеет особого значения.)

Причина в том, что hashCode (а также equals), как определено, является динамическим, например. изменяется всякий раз, когда элемент добавляется или удаляется, а также изменяется, если изменяется хеш-код элемента (что само по себе проблематично для наборов на основе хэшей). Таким образом, набор/список/карта обычно не является хорошим ключом для карты.

Для неизменяемого набора (который на практике также является единственным типом набора, который действительно подходит в качестве ключа карты) хэш-код может быть рассчитан один раз (либо при создании, либо при первом использовании), а затем кэширован (как это делает String). ).

Можно также реализовать такое кэширование для изменяемых наборов, если хеш-коды элементов не меняются: формула достаточно проста, чтобы можно было обновлять значение при каждом добавлении или удалении, не проверяя ничего, кроме добавленного/ удаленный элемент. Но убедитесь, что набор не меняется, пока он используется в качестве ключа на карте.

(Большая часть этого также относится к спискам и картам с их похожими hashCode() формулами.)

person Paŭlo Ebermann    schedule 07.07.2011
comment
спасибо, Пауло. В основном вы подтверждаете мои опасения, что это немного проблематично. Мой набор является окончательным, поэтому подход должен быть в порядке, но это создаст общие накладные расходы, и я пытаюсь выяснить, как этого избежать. - person ib84; 07.07.2011