Upaya awal untuk menghapus Python GIL menghasilkan kinerja yang buruk: Mengapa?

13

Posting ini dari pembuat Python, Guido Van Rossum, menyebutkan upaya awal untuk menghapus GIL dari Python:

Ini telah dicoba sebelumnya, dengan hasil yang mengecewakan, itulah sebabnya saya enggan berusaha keras untuk melakukannya sendiri. Pada tahun 1999 Greg Stein (dengan Mark Hammond?) Menghasilkan garpu Python (1,5 saya percaya) yang menghapus GIL, menggantikannya dengan kunci berbutir halus pada semua struktur data yang bisa berubah. Dia juga mengirimkan tambalan yang menghilangkan banyak ketergantungan pada struktur data global yang bisa berubah, yang saya terima. Namun, setelah benchmarking, ditunjukkan bahwa bahkan pada platform dengan primitif penguncian tercepat (Windows saat itu), memperlambat eksekusi single-threaded hampir dua kali lipat, yang berarti bahwa pada dua CPU, Anda bisa mendapatkan sedikit lebih banyak pekerjaan dilakukan tanpa GIL daripada pada CPU tunggal dengan GIL. Ini tidak cukup, dan patch Greg menghilang. (Lihat Langgan Greg pada kinerja.)

Saya hampir tidak dapat berdebat dengan hasil yang sebenarnya, tetapi saya benar-benar bertanya-tanya mengapa ini terjadi. Agaknya, alasan utama yang menghapus GIL dari CPython sangat sulit adalah karena referensi menghitung sistem manajemen memori. Program Python biasa akan memanggil Py_INCREFdan Py_DECREFribuan atau jutaan kali, menjadikannya titik pertentangan utama jika kita ingin membungkus kunci di sekitarnya.

Tapi, saya tidak mengerti mengapa menambahkan primitif atom akan memperlambat program berulir tunggal . Misalkan kita baru saja memodifikasi CPython sehingga variabel refcount di setiap objek Python adalah sebuah atom primitif. Dan kemudian kita hanya melakukan peningkatan atom (mengambil dan menambah instruksi) ketika kita perlu menambah jumlah referensi. Ini akan membuat referensi Python menghitung thread-safe, dan seharusnya tidak memiliki penalti kinerja pada aplikasi single-threaded, karena tidak akan ada pertengkaran kunci.

Tapi sayangnya, banyak orang yang lebih pintar dari saya telah mencoba dan gagal, jadi jelas saya kehilangan sesuatu di sini. Apa yang salah dengan cara saya melihat masalah ini?

Siler
sumber
1
Perhatikan bahwa operasi refcount bukan satu-satunya tempat yang membutuhkan sinkronisasi. Kutipan tersebut menyebutkan "kunci berbutir halus pada semua struktur data yang bisa berubah-ubah" yang saya duga menyertakan setidaknya mutex untuk setiap daftar dan objek kamus. Juga, saya tidak berpikir operasi integer atom seefisien non-atom setara terlepas dari pertentangan, apakah Anda memiliki sumber untuk itu?
sederhananya, karena operasi atom lebih lambat dari padanan non-atom. Hanya karena itu adalah instruksi tunggal tidak berarti itu sepele di bawah tenda. Lihat ini untuk beberapa diskusi
Móż

Jawaban:

9

Saya tidak terbiasa dengan garpu Greg Stein Python, jadi diskon perbandingan ini sebagai analogi sejarah spekulatif jika Anda mau. Tapi ini persis pengalaman historis dari banyak basis kode infrastruktur yang bergerak dari implementasi single-ke-multi-threaded.

Pada dasarnya setiap implementasi Unix yang saya pelajari pada 1990-an - AIX, DEC OSF / 1, DG / UX, DYNIX, HP-UX, IRIX, Solaris, SVR4, dan SVR4 MP - semuanya berjalan dengan tepat seperti ini "kami masukkan penguncian berbutir halus - sekarang lebih lambat !! " masalah. DBMS yang saya ikuti - DB2, Ingres, Informix, Oracle, dan Sybase - mereka semua juga mengalaminya.

Saya telah mendengar "perubahan ini tidak akan memperlambat kami saat kami menjalankan satu utas" sejuta kali. Tidak pernah berhasil seperti itu. Tindakan sederhana memeriksa kondisi "apakah kita menjalankan multithreaded, atau tidak?" menambahkan overhead nyata, terutama pada CPU yang sangat disalurkan. Operasi atom dan spin-locks sesekali ditambahkan untuk memastikan integritas struktur data bersama harus cukup sering dipanggil, dan mereka sangat lambat. Primitif kunci / sinkronisasi generasi pertama juga lambat. Sebagian besar tim implementasi akhirnya menambahkan beberapa kelas primitif, dalam berbagai "kekuatan", tergantung pada seberapa banyak perlindungan interlock diperlukan di berbagai tempat. Kemudian mereka menyadari di mana mereka awalnya menampar primitif pengunci bukan tempat yang tepat, jadi mereka harus membuat profil, mendesain di sekitar kemacetan yang ditemukan, dan secara sistematis melakukan roto-sampai. Beberapa dari poin ini akhirnya mendapatkan akselerasi OS atau perangkat keras, tetapi seluruh evolusi itu memakan waktu 3-5 tahun, minimal. Sementara itu, versi MP atau MT pincang, kinerja-bijaksana.

Jika tidak, tim pengembangan yang canggih berpendapat bahwa perlambatan seperti itu pada dasarnya adalah fakta kehidupan yang gigih dan tidak bisa diselesaikan. IBM misalnya menolak untuk mengaktifkan AIX untuk SMP setidaknya 5 tahun setelah kompetisi, bersikeras bahwa single-threaded hanya murni lebih baik. Sybase menggunakan beberapa argumen yang sama. Satu-satunya alasan beberapa tim akhirnya muncul adalah karena kinerja single-thread tidak lagi dapat ditingkatkan pada tingkat CPU. Mereka terpaksa memilih MP / MT atau menerima produk yang semakin tidak kompetitif.

Konkurensi aktif adalah KERAS. Dan itu menipu. Semua orang bergegas ke sana berpikir "ini tidak akan terlalu buruk." Kemudian mereka membentur pasir hisap, dan harus melaluinya. Saya telah melihat ini terjadi dengan setidaknya selusin nama-merek, tim yang didanai dengan baik, cerdas. Secara umum tampaknya butuh setidaknya lima tahun setelah memilih multi-thread untuk "kembali ke posisi semula, berdasarkan kinerja" dengan produk MP / MT; sebagian besar masih meningkatkan efisiensi / skalabilitas MP / MT secara bermakna bahkan sepuluh tahun setelah melakukan perubahan.

Jadi spekulasi saya adalah bahwa, tanpa dukungan dan dukungan GvR, tidak ada yang mengambil jalur panjang untuk Python dan GIL-nya. Bahkan jika mereka melakukannya hari ini, itu akan menjadi Python 4.x jangka waktu sebelum Anda akan berkata "Wow! Kami benar-benar melebihi MT punuk!"

Mungkin ada beberapa keajaiban yang memisahkan Python dan runtime dari semua perangkat lunak infrastruktur stateful lainnya - semua runtimes bahasa, sistem operasi, monitor transaksi, dan manajer basis data yang telah berjalan sebelumnya. Tetapi jika demikian, itu unik atau hampir seperti itu. Semua orang yang menghapus setara dengan GIL membutuhkan waktu lebih dari lima tahun, kerja keras dan investasi untuk beralih dari MT-bukan ke MT-hot.

Jonathan Eunice
sumber
2
+1 Butuh waktu semacam itu untuk membuat multi-utas Tcl dengan tim pengembang yang cukup kecil. Kode tersebut adalah MT-safe sebelum itu, tetapi memiliki masalah kinerja yang buruk, sebagian besar dalam manajemen memori (yang saya duga adalah area yang sangat panas untuk bahasa yang dinamis). Pengalaman tidak benar-benar terbawa ke Python dalam hal selain dari istilah yang paling umum; kedua bahasa memiliki model threading yang sama sekali berbeda. Hanya ... mengharapkan pekerjaan keras dan mengharapkan serangga aneh ...
Donal Fellows
-1

Hipotesis liar lainnya: Pada tahun 1999, Linux dan Unix lain tidak memiliki sinkronisasi kinerja seperti sekarang futex(2)( http://en.wikipedia.org/wiki/Futex ). Itu datang sekitar tahun 2002 (dan digabung menjadi 2,6 sekitar tahun 2004).

Karena semua struktur data builtin harus disinkronkan biaya penguncian banyak. Ӎσᶎ sudah menunjukkan, bahwa operasi atom tidak perlu murah.

Tuan
sumber
1
Apakah Anda punya sesuatu untuk mendukung ini? atau ini hampir spekulasi?
1
Kutipan GvR menggambarkan kinerja "pada platform dengan primitif penguncian tercepat (Windows saat itu)" sehingga kunci lambat di Linux tidak relevan.