Warum steigt die Geschwindigkeit, um 400.000.000 Zufallszahlen zu generieren?

9

Ich erzeuge auf einem Intel i7 mit 4 Kernen (8 Threads mit Hyperthreading) auf macOS mit 8 GB RAM etwa 400.000.000 (400 Millionen) Zufallszahlen parallel.

Aber ich erzeuge auch 400.000.000 Zufallszahlen auf einem DigitalOcean-Server mit 20 Kernen auf Debian mit 64 GB RAM.

Hier ist der Code:

%Vor%

Dies sind die Ergebnisse der Benchmark:

%Vor%

Je mehr Zufallszahlen generiert werden, desto mehr kann die Parallelität der 20-Kern-CPU genutzt werden. Daher nimmt die "Zunahme der Zeiten" von 8 Kern auf 20 Kern mit der Zeit zu.

Nach 300 Millionen Zufallszahlen nimmt dies jedoch ab und steigt wieder auf bis zu 800 Millionen (habe ich nicht weiter getestet).

Warum ist das? Gibt es einen bestimmten Grund? War es nur zufällig? (Ich habe das zweimal wiederholt und habe beide Male das gleiche Ergebnis erhalten)

BEARBEITEN: Wenn es einen Unterschied macht, verwende ich die Funktion time , um die Ausführung des Skripts zeitlich zu bestimmen. Außerdem ist das Betriebssystem auf beiden Rechnern nicht identisch (8 Kern - macOS, 20 Kern - Debian).

    
TajyMany 12.06.2017, 09:01
quelle

1 Antwort

1

Zwei mögliche Erklärungen kommen in den Sinn.

Dies könnte ein Artefakt der Garbage Collection sein. Ein einfaches Experiment wäre, GC auszuschalten und zu sehen, ob das "Dip" weiterhin besteht:

%Vor%

Eine andere Möglichkeit ist, dass dies ein Artefakt des Listenwachstums ist, indem realloc () unter der Haube verwendet wird. Die implementierten Listen sind Arrays fester Länge von Zeigern. Wenn map () die Liste mit append () erweitert, wird der C-Funktionsaufruf realloc () regelmäßig aufgerufen, um das Array von Zeigern zu ändern. Oft ist dieser Anruf sehr günstig, da keine Daten verschoben werden müssen. Wenn jedoch auch nur ein einziges Byte im Speicher die Größenänderung "blockiert", müssen die Daten alle verschoben werden. Dies ist sehr teuer und könnte Ihr "Dip" verursachen, wenn zu diesem Zeitpunkt in der Multiprozessorverarbeitung ein blockierendes Byte erzeugt wird.

Um diese Hypothese zu testen, könnten Sie imap () anstelle von map () verwenden und die Ergebnisse in collections.deque () einreihen anstelle einer list () . Die Deque-Implementierung verwendet reloc nicht, so dass ihre Leistung angesichts von fragmentiertem Speicher konsistent ist (intern werden nur wiederholte Aufrufe von malloc () an Speicherblöcke mit fester Länge vorgenommen ).

    
Raymond Hettinger 09.07.2017 14:58
quelle