Alle diese Ergebnisse wurden mit CPython 3.5.2 erhalten.Merkwürdige Leistungen für Mengenoperationen
Ich bemerkte seltsame Leistungen für einige Operationen der set
Klasse.
Ich habe die Zeit gemessen, die benötigt wird, um die Vereinigung von zwei Mengen, die nur ganze Zahlen enthalten, durchzuführen. Diese Zeit hängt natürlich von den Größen der Sets ab. Überraschenderweise hängt es auch von der "Dichte" der ganzen Zahlen ab. Hier ist eine grafische Darstellung:
Die x-Achse ist die Summe der Umfänge der beiden Sätze (die voneinander unabhängig und zufällig ausgewählt wurden, für jede Erfahrung). Die y-Achse ist die Zeit in Sekunden (in logarithmischer Skala).
Eine Dichte d
bedeutet, dass die Sätze instanziiert wurden, indem N
ganze Zahlen von insgesamt N/d
ganzen Zahlen genommen wurden. Mit anderen Worten, für eine Dichte von 0,5 nehmen wir die Hälfte der ganzen Zahlen eines Intervalls an, während wir für eine Dichte von 0,1 ein Zehntel der ganzen Zahlen eines (größeren) Intervalls nehmen.
Hier ist ein minimaler Code, um einige Ergebnisse zu erhalten (bei Bedarf kann ich den vollen Code, den ich für das Diagramm verwendet habe, aber es ist länger).
import time
import random
import numpy
def get_values(size, density):
return set(random.sample(range(int(size/density)), size))
def perform_op(size, density):
values1 = get_values(size, density)
values2 = get_values(size, density)
t = time.time()
result = values1 | values2
return time.time()-t
size = 10000000
for density in [0.05, 0.1, 0.5, 0.99]:
times = [perform_op(size, density) for _ in range(10)]
print('density: %.2f, mean time: %.4f, standard deviation: %.4f' % (density, numpy.mean(times), numpy.std(times)))
Union:
density: 0.05, time: 0.9846, standard deviation: 0.0440
density: 0.10, time: 1.0141, standard deviation: 0.0204
density: 0.50, time: 0.5477, standard deviation: 0.0059
density: 0.99, time: 0.3440, standard deviation: 0.0020
Es gibt etwa einen Faktor 3 für die Rechenzeit zwischen dem schnellsten und dem langsamsten, mit Sätzen eine gleiche Größe aufweisen. Es gibt auch viel mehr Variabilität für niedrige Dichten.
Eine lustige Sache ist, dass für die Kreuzung (ersetzen values1 | values2
durch values1 & values2
in perform_op
-Funktion), haben wir auch nicht konstant Leistungen, aber das Muster ist anders:
density: 0.05, time: 0.3928, standard deviation: 0.0046
density: 0.10, time: 0.4876, standard deviation: 0.0041
density: 0.50, time: 0.5975, standard deviation: 0.0127
density: 0.99, time: 0.3806, standard deviation: 0.0015
ich nicht andere Set-Operationen testen habe .
Ich verstehe nicht, warum es solche Unterschiede gibt. Soweit ich weiß, werden Python-Sets mit Hash-Tabellen implementiert, so dass die Dichte der ganzen Zahlen keine Rolle spielt, solange ihre Hashes gut verteilt sind.
Woher kommen diese unterschiedlichen Leistungen?
Die Effizienz eines Hash-Sets hängt von der Anzahl der Elemente ab, die in dasselbe Bucket gerastert werden. Dies hängt wiederum von der Größe des Sets selbst und der Verteilung der Zahlen ab. Ich lasse jemanden, der mit der Implementierung von 'set' vertrauter ist, eine richtige Antwort geben. –