Mir ist aufgefallen, dass meine Python-Anwendung beim Ausführen viel langsamer ist als python:2-alpine3.6
ohne Docker unter Ubuntu. Ich habe zwei kleine Benchmark-Befehle gefunden, und es gibt einen großen Unterschied zwischen den beiden Betriebssystemen, sowohl wenn ich sie auf einem Ubuntu-Server ausführe als auch wenn ich Docker für Mac verwende.
$ BENCHMARK="import timeit; print(timeit.timeit('import json; json.dumps(list(range(10000)))', number=5000))"
$ docker run python:2-alpine3.6 python -c $BENCHMARK
7.6094589233
$ docker run python:2-slim python -c $BENCHMARK
4.3410820961
$ docker run python:3-alpine3.6 python -c $BENCHMARK
7.0276606959
$ docker run python:3-slim python -c $BENCHMARK
5.6621271420
Ich habe auch den folgenden 'Benchmark' ausprobiert, der Python nicht verwendet:
$ docker run -ti ubuntu bash
root@6b633e9197cc:/# time $(i=0; while (( i < 9999999 )); do (( i ++
)); done)
real 0m39.053s
user 0m39.050s
sys 0m0.000s
$ docker run -ti alpine sh
/ # apk add --no-cache bash > /dev/null
/ # bash
bash-4.3# time $(i=0; while (( i < 9999999 )); do (( i ++ )); done)
real 1m4.277s
user 1m4.290s
sys 0m0.000s
Was könnte diesen Unterschied verursachen?
ubuntu
performance
docker
alpine-linux
Underyx
quelle
quelle
Antworten:
Ich habe den gleichen Benchmark wie Sie ausgeführt und nur Python 3 verwendet:
was zu mehr als 2 Sekunden Unterschied führt:
Alpine verwendet eine andere Implementierung von
libc
( Basissystembibliothek ) als das musl- Projekt ( Spiegel-URL ). Es gibt viele Unterschiede zwischen diesen Bibliotheken . Infolgedessen kann jede Bibliothek in bestimmten Anwendungsfällen eine bessere Leistung erbringen.Hier ist ein Unterschied zwischen diesen Befehlen oben . Die Ausgabe beginnt sich von Zeile 269 zu unterscheiden. Natürlich gibt es verschiedene Adressen im Speicher, aber ansonsten ist es sehr ähnlich. Die meiste Zeit wird offensichtlich damit verbracht, auf das
python
Ende des Befehls zu warten .Nach der Installation
strace
in beiden Containern erhalten wir eine interessantere Ablaufverfolgung (ich habe die Anzahl der Iterationen im Benchmark auf 10 reduziert).Beispielsweise
glibc
ist das Laden von Bibliotheken in der folgenden Weise (Leitung 182):Der gleiche Code in
musl
:Ich sage nicht, dass dies der Hauptunterschied ist, aber die Reduzierung der Anzahl der E / A-Vorgänge in Kernbibliotheken könnte zu einer besseren Leistung beitragen. Aus dem Diff können Sie ersehen, dass das Ausführen des gleichen Python-Codes zu geringfügig unterschiedlichen Systemaufrufen führen kann. Wahrscheinlich könnte das Wichtigste bei der Optimierung der Schleifenleistung getan werden. Ich bin nicht qualifiziert genug, um beurteilen zu können, ob das Leistungsproblem durch Speicherzuweisung oder eine andere Anweisung verursacht wird.
glibc
mit 10 Iterationen:musl
mit 10 Iterationen:musl
ist um 0.0028254222124814987 Sekunden langsamer. Da der Unterschied mit der Anzahl der Iterationen zunimmt, würde ich annehmen, dass der Unterschied in der Speicherzuordnung von JSON-Objekten liegt.Wenn wir den Benchmark auf den reinen Import reduzieren, stellen
json
wir fest, dass der Unterschied nicht so groß ist:Das Laden von Python-Bibliotheken sieht vergleichbar aus. Generieren
list()
erzeugt größere Unterschiede:Offensichtlich ist die teuerste Operation
json.dumps()
, die auf Unterschiede in der Speicherzuordnung zwischen diesen Bibliotheken hindeuten könnte.Wenn Sie sich den Benchmark noch einmal ansehen ,
musl
ist die Speicherzuweisung wirklich etwas langsamer:Ich bin mir nicht sicher, was mit "große Zuweisung" gemeint ist, aber es
musl
ist fast 2 × langsamer, was bedeutsam werden kann, wenn Sie solche Vorgänge Tausende oder Millionen Mal wiederholen.quelle