8
votes

Devrais-je jeter java.util.hashasset en faveur de CompaceThashSet?

J'ai trouvé qu'il y avait une implémentation d'un ensemble qui utilise des hachages (avec toutes les conséquences utiles, telles que O (1) pour contient () etc.) prétendait être plus efficace que java.util.hastryset dans tous les aspects:

http: //ontopia.wordpress .COM / 2009/09/23 / A-FASTER-et-PLUS-COMPACT-SET /

http://alias-i.com/ Lingpipe / Docs / API / COM / ALIASI / UTIL / COMPACTHASHSET.HTML

serait-il alors une bonne idée de cesser d'arrêter d'utiliser java.util.hashashset complètement où que j'ai besoin d'un java.util.set en faveur de com. aliasi.Util.compAcastSet ?


11 commentaires

Pourquoi ajouter une autre dépendance du pot à votre projet lorsque hashset fonctionne parfaitement? Sauf si vous développez que vous développez des applications de latence faible et que vous savez que vous avez des problèmes de performance ou de mémoire tas


Avez-vous des problèmes de performance où vous utilisez des hashsets? Si c'est le cas, faites vos propres points de repère et voyez ce que c'est bon. Ensuite, vous pouvez décider si vous devez basculer ou non.


Votre premier lien montre une très bonne comparaison. Si CompaceTharaseSet offre tout ce qu'un hashset offre et peut-être plus, pourquoi pas simplement l'utiliser?


@ NJZK2 Je vois votre point et non, je n'ai pas encore de problèmes de performance avec hashset (au moins il n'y a pas de problème à ce que je suis au courant), mais si j'aurai rencontré ces problèmes et que je devrai utiliser la nouvelle mise en œuvre efficace de toute façon, Sera-t-il alors logique de se débarrasser de hashset s dans mon code? Je veux dire, mis à part la performance, vous risquez d'utiliser une implémentation différente d'un ensemble qui pourrait potentiellement être nocif?


@MOHAMMAMMAD: Parce que depuis que les personnes encore moins utilisent, il est beaucoup plus enclin à contenir des bugs qui n'ont peut-être pas encore été découverts.


Si vous lisez les commentaires dans le premier lien, l'un des demandes d'utilisateurs Hashset est plus rapide pour leur cas d'utilisation. Longue histoire courte, il n'y a pas d'ensemble "le plus rapide". Vous devez choisir le bon pour votre cas d'utilisateur (basé sur le calendrier réel des scénarios du monde réel).


Intéressant que GUAVA dispose également d'une compacthacastSet si vous souhaitez inclure un pot supplémentaire qui fournit encore plus de fonctionnalités et sera plus largement utilisé par la communauté Java


Cela dépend vraiment de ce que vous optimisez; Cela va être un compromis, peu importe. Si vous n'avez pas Benchmarks réels pour prouver que l'un vaut mieux pour votre cas d'utilisation que l'autre, vous n'avez pas vraiment de raison pour vous attendre à ce que l'un soit préférable à un autre.


De plus, si vous lisez le deuxième lien, le CompaceThrasheSet est pas compatible avec le hashset. Entre autres choses, NULL ne peut pas être utilisée et vous pourriez obtenir des exceptions classiques de classe dans certains scénarios qui ne voudraient pas jeter pour Hashset.


@Brad Il est étrange que cette classe ait été écrite en 2012, j'utilise une version beaucoup plus récente de Guava et je n'ai pas entendu parler de cette classe, et d'ailleurs, ne l'avez pas dans mon pot de goyave (téléchargé d'un repo public. avec Maven) du tout.


@Susei: Si vous regardez le lien Brad, vous verrez qu'il relie directement à un changement qui a ajouté cette classe, et vous verrez mon nom comme l'auteur de changement. Nous n'exposons pas cette classe à Guava parce que les compromis sont complexes, et cela n'est pas évident même pour nous lorsque les différentes versions sont appropriées.


3 Réponses :


3
votes

Cela dépend.

traitez-vous avec de très grands ensembles et de nombreux opérations d'insertion ou de lecture? Cette nouvelle mise en œuvre a réduit le temps pendant une demi-million d'opérations. C'est une grande amélioration, mais si vous ne faites que quelques milliers d'opérations ou une douzaine, cela se transforme rapidement en micro-optimisation.

Les tests affichés inséraient également un long dans l'ensemble. Les performances pour l'utilisation des heures d'exécution et de la mémoire peuvent changer si vous stockez autre chose dans l'ensemble.

Si vous avez un cas d'utilisation qui profite de la modification de manière statistiquement significative, utilisez-le.


0 commentaires

3
votes

Option 1: Ne vous souciez pas . Si vous regardez dans la mise en œuvre de Hashset Java, vous découvrez qu'il utilise simplement un hashmap en interne: xxx

qui est une implémentation rapide, toutefois, chaque entrée de définition a une référence à une valeur, qui n'est pas avait besoin. D'où la consommation de mémoire. Ma première option est de "ne pas s'en soucier", car j'espère qu'à l'avenir, quelqu'un fournira un hashset amélioré dans le JDK. Les ingénieurs logiciels doivent toujours avoir de l'espoir et une attitude positive :)

dans la logique de programme normale, je m'envoie toujours aux normes fournies autant que possible et utilisez ce qui est disponible. Cela évite l'effet que chaque programmeur utilise sa propre "mise en oeuvre de choix préférée" ou, encore pire, fait une longue recherche quelle est la meilleure implémentation de hashset à utiliser;)

Oracle a-t-il un billet de bug ouvert Pour le pauvre hashmap? Impossible de trouver une ....

Option 2: Care . Si vous n'êtes pas sur la valeur logique des entreprises, mais dans un code de middleware technique, les performances peuvent compter. Ensuite, il existe différentes options. La CompaceThashmap dans Google Guava est une. Une autre belle bibliothèque est la collections primitives haute performance . Dans HPPC, vous trouvez des ensembles pour chaque type primitif. Je pense que vous trouverez également d'autres choses qui correspondent à votre objectif particulier. Tous les remplaçants de HASHMAP peuvent avoir exactement la même sémantique que le haschmap orginal.

Donc, je ne remplacer personnellement jamais Java.util.hashmap juste "par défaut".



9
votes

Commençons un petit jeu de référence.

Les repères sont basés sur des repères de l'article original, mais utilisez des outils modernes. P>

Set implementation   Speed           Memory footprint
                     Score Units     +UCOops -UseCompressedOops
CompactHashSet       828   ns/op     8.4     16.8    bytes/elem
HashSet              676   ns/op     37.4    60.3    bytes/elem
HPPC Set             853   ns/op     10.5    18.9    bytes/elem
Koloboke Set         587   ns/op     8.4     16.8    bytes/elem
GuavaCompactHashSet  874   ns/op     25.9    37.4    bytes/elem


6 commentaires

Je ne comprends pas comment un CompacthacastSet peut être presque 4x inférieur à un hashset lorsqu'il utilise des entrées liées de la même manière.


Je vois ... c'est un autre CompaCharasset , je voulais dire celui de Google.


@maaArtinus a mis à jour la réponse. Pour être honnête, je ne comprends pas pourquoi java.util.hashashset largement critiqué pour "lazy" HASHMAP -Deleging implémentatif fonctionne si bien contre des implémentations spécialement optimisées. Peut-être qu'il y a une erreur dans les points de repère?


Merci pour la référence complète! Ma critique sur Java.Util.Hashashset était particulièrement en ce qui concerne l'efficacité de la mémoire.


1. Il y a des compromis. Vous pouvez utiliser un dense hashmap et le rendre plus petit et plus lent. 2. Vos données sont parfaitement aléatoires, ce qui peut favoriser certaines implémentations. 3. Votre "recherche" ne trouve difficilement rien, ce qui peut créer un biais aussi. 4. La même chose pour "supprimer". 5. En réalité, de nombreux points de repère différents seraient nécessaires pour obtenir une réponse complète (mais que pourrions-nous faire avec ce nombre de chiffres).


@cruftex the hashmap.enterry semble gaspillé pour un hashset , mais sur un JVM 32 bits ou avec "compressressuops", le champ inutile valeur est libre en raison de l'alignement. COMPACTHASTSET et HASH , où ce dernier est utilisé dans le HM pour la vitesse (en évitant la comparaison de la clé).