Saya telah menjalankan tolok ukur yang sama seperti yang Anda lakukan, hanya menggunakan Python 3:
$ docker run python:3-alpine3.6 python --version
Python 3.6.2
$ docker run python:3-slim python --version
Python 3.6.2
menghasilkan perbedaan lebih dari 2 detik:
$ docker run python:3-slim python -c "$BENCHMARK"
3.6475560404360294
$ docker run python:3-alpine3.6 python -c "$BENCHMARK"
5.834922112524509
Alpine menggunakan implementasi berbeda libc
(pustaka sistem dasar) dari proyek musl ( mirror URL ). Ada banyak perbedaan di antara perpustakaan-perpustakaan itu . Akibatnya, setiap perpustakaan mungkin berkinerja lebih baik dalam kasus penggunaan tertentu.
Berikut ini perbedaan strace antara perintah-perintah di atas . Outputnya mulai berbeda dari baris 269. Tentu saja ada alamat yang berbeda dalam memori, tetapi sebaliknya sangat mirip. Sebagian besar waktu jelas dihabiskan menunggu python
perintah selesai.
Setelah memasang strace
ke kedua kontainer, kita bisa mendapatkan jejak yang lebih menarik (saya telah mengurangi jumlah iterasi dalam benchmark menjadi 10).
Misalnya, glibc
memuat pustaka dengan cara berikut (baris 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
Kode yang sama di 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
Saya tidak mengatakan ini adalah perbedaan utama, tetapi mengurangi jumlah operasi I / O di perpustakaan inti mungkin berkontribusi pada kinerja yang lebih baik. Dari diff Anda dapat melihat bahwa mengeksekusi kode Python yang sama dapat menyebabkan panggilan sistem yang sedikit berbeda. Mungkin yang paling penting dapat dilakukan dalam mengoptimalkan kinerja loop. Saya tidak cukup memenuhi syarat untuk menilai apakah masalah kinerja disebabkan oleh alokasi memori atau instruksi lainnya.
glibc
dengan 10 iterasi:
write(1, "0.032388824969530106\n", 210.032388824969530106)
musl
dengan 10 iterasi:
write(1, "0.035214247182011604\n", 210.035214247182011604)
musl
lebih lambat oleh 0,0028254222124814987 detik. Sebagai perbedaan tumbuh dengan jumlah iterasi, saya berasumsi perbedaannya adalah dalam alokasi memori objek JSON.
Jika kami mengurangi tolok ukur hanya untuk mengimpor, json
kami melihat perbedaannya tidak terlalu besar:
$ 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
Memuat pustaka Python terlihat sebanding. Menghasilkan list()
menghasilkan perbedaan yang lebih besar:
$ 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
Jelas operasi yang paling mahal adalah json.dumps()
, yang mungkin menunjukkan perbedaan alokasi memori antara perpustakaan-perpustakaan itu.
Melihat lagi patokannya ,
musl
alokasi alokasi memori benar-benar sedikit lebih lambat:
musl | glibc
-----------------------+--------+--------+
Tiny allocation & free | 0.005 | 0.002 |
-----------------------+--------+--------+
Big allocation & free | 0.027 | 0.016 |
-----------------------+--------+--------+
Saya tidak yakin apa yang dimaksud dengan "alokasi besar", tetapi musl
hampir 2 × lebih lambat, yang mungkin menjadi signifikan ketika Anda mengulangi operasi seperti itu ribuan atau jutaan kali.