Ich habe den gleichen Benchmark wie Sie mit Python 3 ausgeführt:
$ docker run python:3-alpine3.6 python --version Python 3.6.2 $ docker run python:3-slim python --version Python 3.6.2
was zu mehr als 2 Sekunden Unterschied führt:
$ docker run python:3-slim python -c "$BENCHMARK" 3.6475560404360294 $ docker run python:3-alpine3.6 python -c "$BENCHMARK" 5.834922112524509
Alpine verwendet eine andere Implementierung libc
( Basissystembibliothek ) als das Musl- Projekt . Es gibt viele Unterschiede zwischen diesen Bibliotheken . Daher kann jede Bibliothek in bestimmten Anwendungsfällen bessere Ergebnisse erzielen.
Hier ist ein Unterschied zwischen diesen Befehlen . Die Ausgabe beginnt sich von Zeile 269 zu unterscheiden. Natürlich gibt es unterschiedliche Adressen im Speicher, ansonsten ist sie jedoch sehr ähnlich. Die meiste Zeit wird offensichtlich auf das python
Ende des Befehls gewartet .
Nach der Installation strace
in beiden Containern können wir eine interessantere Spur erhalten (ich habe die Anzahl der Iterationen im Benchmark auf 10 reduziert).
Zum Beispiel glibc
wird das Laden von Bibliotheken in der folgenden Weise (Leitung 182):
openat(AT_FDCWD, "/usr/local/lib/python3.6", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3 getdents(3, /* 205 entries */, 32768) = 6824 getdents(3, /* 0 entries */, 32768) = 0
gleicher Code in musl
:
open("/usr/local/lib/python3.6", O_RDONLY|O_DIRECTORY|O_CLOEXEC) = 3 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 getdents64(3, /* 62 entries */, 2048) = 2040 getdents64(3, /* 61 entries */, 2048) = 2024 getdents64(3, /* 60 entries */, 2048) = 2032 getdents64(3, /* 22 entries */, 2048) = 728 getdents64(3, /* 0 entries */, 2048) = 0
Ich sage nicht, dass dies der entscheidende Unterschied ist, aber die Reduzierung der E / A-Anzahl in Core-Bibliotheken könnte zu einer besseren Leistung beitragen. Aus dem Vergleich können Sie erkennen, dass die Ausführung desselben Python-Codes zu leicht unterschiedlichen Systemaufrufen führen kann. Das Wichtigste könnte wohl bei der Optimierung der Schleifenleistung gemacht werden. Ich bin nicht qualifiziert, um zu beurteilen, ob das Leistungsproblem durch Speicherzuordnung oder andere Anweisungen verursacht wird.
glibc
mit 10 Iterationen:write(1, "0.032388824969530106\n", 210.032388824969530106)
musl
mit 10 Iterationen:write(1, "0.035214247182011604\n", 210.035214247182011604)
musl
ist 0,0028254222124814987 Sekunden langsamer. Da der Unterschied mit der Anzahl der Iterationen zunimmt, gehe ich davon aus, dass der Unterschied in der Speicherzuordnung von JSON-Objekten liegt.
Wenn wir den Benchmark auf das reine Importieren reduzieren, stellen json
wir fest, dass der Unterschied nicht so groß ist:
$ BENCHMARK="import timeit; print(timeit.timeit('import json;', number=5000))" $ docker run python:3-slim python -c "$BENCHMARK" 0.03683806210756302 $ docker run python:3-alpine3.6 python -c "$BENCHMARK" 0.038280246779322624
Das Laden von Python-Bibliotheken sieht vergleichbar aus. Generieren list()
erzeugt größere Unterschiede:
$ BENCHMARK="import timeit; print(timeit.timeit('list(range(10000))', number=5000))" $ docker run python:3-slim python -c "$BENCHMARK" 0.5666235145181417 $ docker run python:3-alpine3.6 python -c "$BENCHMARK" 0.6885563563555479
Offensichtlich ist der teuerste Vorgang json.dumps()
, der auf Unterschiede in der Speicherzuordnung zwischen diesen Bibliotheken hinweisen könnte.
Wenn man den Benchmark noch einmal betrachtet, musl
ist die Speicherzuordnung wirklich etwas langsamer:
musl | glibc -----------------------+--------+--------+ Tiny allocation & free | 0.005 | 0.002 | -----------------------+--------+--------+ Big allocation & free | 0.027 | 0.016 | -----------------------+--------+--------+
Ich bin mir nicht sicher, was mit "großer Zuteilung" gemeint ist, aber es musl
ist fast um das 2-fache langsamer, was bedeutsam werden kann, wenn Sie solche Operationen tausend- oder millionenfach wiederholen.