Sets und Diktate sind für verschiedene Anwendungsfälle optimiert. Die Hauptverwendung eines Sets ist das schnelle Testen der Mitgliedschaft, was auftragsunabhängig ist.Für Diktate sind die Kosten für die Suche die kritischste Operation, und es ist wahrscheinlicher, dass der Schlüssel vorhanden ist. Bei Mengen ist das Vorhandensein oder Fehlen eines Elements nicht im Voraus bekannt, und daher muss die Mengenimplementierung sowohl für den gefundenen als auch für den nicht gefundenen Fall optimiert werden. Einige Optimierungen für allgemeine Mengenoperationen wie Vereinigung und Schnittmenge machen es außerdem schwierig, die Satzreihenfolge beizubehalten, ohne die Leistung zu beeinträchtigen.
Während beide Datenstrukturen auf Hash basieren, ist es ein weit verbreitetes Missverständnis, dass Mengen nur als Dikte mit Nullwerten implementiert werden. Bereits vor der kompakten Diktatimplementierung in CPython 3.6 unterschieden sich die Set- und Diktatimplementierungen erheblich, wobei nur wenig Code wiederverwendet wurde. Zum Beispiel verwenden Diktate eine randomisierte Prüfung, aber Sätze verwenden eine Kombination aus linearer Prüfung und offener Adressierung, um die Cache-Lokalität zu verbessern. Die anfängliche lineare Sonde (standardmäßig 9 Schritte in CPython) überprüft eine Reihe benachbarter Schlüssel / Hash-Paare und verbessert die Leistung, indem die Kosten für die Behandlung von Hash-Kollisionen gesenkt werden. Aufeinanderfolgender Speicherzugriff ist billiger als Streusonden.
dictobject.c
- master , v3.5.9
setobject.c
- master , v3.5.9
- issue18771 - Änderungssatz zur Reduzierung der Kosten für Hash-Kollisionen für festgelegte Objekte in Python 3.4.
Theoretisch wäre es möglich , die Set-Implementierung von CPython so zu ändern, dass sie dem kompakten Diktat ähnelt. In der Praxis gibt es jedoch Nachteile, und namhafte Kernentwickler waren gegen eine solche Änderung.
Sätze bleiben ungeordnet. (Warum? Die Verwendungsmuster sind unterschiedlich. Auch unterschiedliche Implementierung.)
- Guido van Rossum
Sets verwenden einen anderen Algorithmus, der nicht so geändert werden kann, um die Einfügereihenfolge beizubehalten. Set-to-Set-Vorgänge verlieren ihre Flexibilität und Optimierungen, wenn eine Bestellung erforderlich ist. Mengenmathematik wird als ungeordnete Menge definiert. Kurz gesagt, die Bestellung von Sets liegt nicht in unmittelbarer Zukunft.
- Raymond Hettinger
Eine ausführliche Diskussion darüber, ob Sets für 3.7 komprimiert werden sollen, und Antworten darauf, warum dagegen entschieden wurde, finden Sie in den Python-Dev-Mailinglisten.
Zusammenfassend sind die Hauptpunkte, dass die Verwendungsmuster unterschiedlich sind (Einfügungsreihenfolgen wie ** kwargs sind nützlich , weniger für Sets), die Platzersparnis für das Komprimieren von Sets ist weniger bedeutend (da nur Schlüssel- und Hash-Arrays vorhanden sind verdichten (im Gegensatz zu Schlüsseln, Hashes und Werten), und die oben erwähnte lineare Abtastoptimierung in Sätzen ist mit einer kompakten Implementierung nicht kompatibel.
Ich werde den Beitrag von Raymond unten wiedergeben, der die wichtigsten Punkte abdeckt.
Am 14. September 2016 um 15:50 Uhr schrieb Eric Snow:
Dann mache ich dasselbe mit Sets.
Sofern ich nicht falsch verstanden habe, war Raymond dagegen, eine ähnliche Änderung am Set vorzunehmen.
Das stimmt. Hier sind ein paar Gedanken zu diesem Thema, bevor die Leute wild werden.
Für das kompakte Diktat war die Platzersparnis ein Nettogewinn, da der zusätzliche Platzbedarf der Indizes und die Gesamtzuordnung für die Schlüssel- / Wert- / Hash-Arrays durch die verbesserte Dichte der Schlüssel- / Wert- / Hash-Arrays mehr als ausgeglichen wurden. Für Sets war das Netz jedoch viel ungünstiger, da wir immer noch die Indizes und die Gesamtzuordnung benötigen, aber die Raumkosten nur durch Verdichtung von nur zwei der drei Arrays ausgleichen können. Mit anderen Worten, das Komprimieren ist sinnvoller, wenn Sie Platz für Schlüssel, Werte und Hashes verschwendet haben. Wenn Sie einen dieser drei verlieren, ist er nicht mehr zwingend.
Das Verwendungsmuster für Sets unterscheidet sich von Diktaten. Ersteres hat mehr Hit-or-Miss-Lookups. Letzteres hat tendenziell weniger fehlende Schlüsselsuchen. Einige der Optimierungen für die Set-to-Set-Vorgänge machen es außerdem schwierig, die Set-Reihenfolge beizubehalten, ohne die Leistung zu beeinträchtigen.
Ich verfolgte einen alternativen Weg, um die Set-Leistung zu verbessern. Anstatt zu komprimieren (was nicht viel Platz einbrachte und die Kosten für eine zusätzliche Indirektion verursachte), fügte ich eine lineare Prüfung hinzu, um die Kosten für Kollisionen zu senken und die Cache-Leistung zu verbessern. Diese Verbesserung ist nicht kompatibel mit dem von mir für Wörterbücher empfohlenen Komprimierungsansatz.
Derzeit ist die Nebenwirkung der Bestellung auf Wörterbücher nicht garantiert, daher ist es verfrüht, darauf zu bestehen, dass auch die Sätze geordnet werden. Die Dokumente enthalten bereits einen Link zu einem Rezept zum Erstellen eines OrderedSet (
https://code.activestate.com/recipes/576694/ ), aber es scheint, dass die Aufnahme nahezu Null war. Nachdem Eric Snow uns ein schnelles OrderedDict zur Verfügung gestellt hat, ist es einfacher als je zuvor, ein OrderedSet aus MutableSet und OrderedDict zu erstellen, aber ich habe auch hier kein wirkliches Interesse festgestellt, da typische Set-to-Set-Datenanalysen dies nicht wirklich tun brauchen oder kümmern sich um die Bestellung. Ebenso ist die primäre Verwendung von schnellen Mitgliedschaftstests auftragsunabhängig.
Ich denke jedoch, dass es Raum gibt, PyPI um alternative Set-Implementierungen zu erweitern. Insbesondere gibt es einige interessante Sonderfälle für bestellbare Daten, bei denen Set-to-Set-Vorgänge durch Vergleichen ganzer Tastenbereiche beschleunigt werden können (siehe
https://code.activestate.com/recipes/230113-implementation-of- setzt-mit-sortierten-Listen
für einen Startpunkt). IIRC, PyPI hat bereits Code für Set-ähnliche Bloom-Filter und Kuckuck-Hashing.
Ich verstehe, dass es aufregend ist, einen großen Codeblock in den Python-Kern aufgenommen zu haben, aber das sollte nicht für Schleusen geöffnet werden, um größere Änderungen an anderen Datentypen vorzunehmen, es sei denn, wir sind sicher, dass dies gerechtfertigt ist.
- Raymond Hettinger
Von [Python-Dev] Python 3.6 wird dict kompakt und erhält eine private Version; und Schlüsselwörter werden im September 2016 bestellt.