gh-116167: Mengizinkan penonaktifan GIL
(github.com/python)- CPython PR #116338 menggabungkan perubahan yang memungkinkan build free-threaded menonaktifkan GIL dengan
PYTHON_GIL=0atau-X gil=0kepython:main - Untuk mempertahankan kemungkinan menyalakan kembali GIL saat runtime, struktur data terkait GIL tetap diinisialisasi seperti biasa, dan penonaktifan dilakukan dengan menyetel flag saat startup agar
take_gil()dandrop_gil()langsung mengembalikan hasil lebih awal - Dalam pemeriksaan awal, dengan setelan
PYTHON_GIL=0, beberapa pengujian dan program kecil yang tidak memakai thread berjalan normal, dan program thread yang sangat dasar kadang-kadang berjalan, tetapi seluruh test suite cepat crash ditest_asyncio - Selama proses review, pengujian
PYTHON_GIL, dokumentasi, opsi-X gil, dan refleksi kesys.flagsditambahkan, serta penanganan setelan juga diperbaiki agarPYTHON_GIL=1memaksa pengaktifan GIL - Pekerjaan lanjutan dipisahkan menjadi masalah menyalakan kembali GIL saat memuat ekstensi yang tidak kompatibel dan masalah menonaktifkan GIL secara default, dan perubahan ini menambahkan permukaan kontrol GIL pada build free-threaded Python 3.13
Perubahan yang digabungkan
- CPython PR #116338 membahas perubahan
gh-116167: Allow disabling the GIL with PYTHON_GIL=0 or -X gil=0 colesburymenggabungkannya kepython:mainpada 11 Maret 2024- Skala perubahan ditandai sebagai 12 file, 163 baris ditambahkan, 1 baris dihapus
- Fitur yang dituju adalah opsi eksekusi untuk menonaktifkan GIL pada build free-threaded, bukan build biasa
Cara menonaktifkan GIL
- Pada build free-threaded, GIL dapat dinonaktifkan dengan setelan berikut
PYTHON_GIL=0-X gil=0
- Agar GIL bisa dinyalakan kembali saat runtime, semua struktur data terkait GIL diinisialisasi seperti biasa
- Penonaktifan aktual dilakukan dengan cara menyetel flag saat startup
- Karena flag ini,
take_gil()dandrop_gil()langsung mengembalikan hasil lebih awal
- Karena flag ini,
- Saat review, commit untuk menyetel
enable_gildengan benar ketikaPYTHON_GIL=1juga ditambahkan
Pengujian dan keterbatasan saat ini
- Dengan setelan
PYTHON_GIL=0, beberapa pengujian dan program kecil diperiksa- Pengujian dan program kecil yang tidak menggunakan thread dikonfirmasi berjalan normal
- Program thread yang sangat dasar terkadang berjalan
- Seluruh test suite cepat crash, dan lokasinya dicatat di
test_asyncio - Dengan perintah
!buildbot nogil, pengujian builder terkait NoGIL dijadwalkan beberapa kalix86-64 MacOS Intel ASAN NoGIL PRx86-64 MacOS Intel NoGIL PRARM64 MacOS M1 Refleaks NoGIL PRARM64 MacOS M1 NoGIL PRAMD64 Ubuntu NoGIL Refleaks PRAMD64 Ubuntu NoGIL PRAMD64 Windows Server 2022 NoGIL PR
Cakupan yang ditambahkan selama review
corona10menyarankan bahwa ada nilai dalam menambahkan pengujian variabel lingkungan keLib/test/test_cmd_line.py- Setelah itu commit berikut ditambahkan
Add test for PYTHON_GIL in test_cmd_lineSet enable_gil properly when PYTHON_GIL=1Don't add 'enable_gil' to test_embed in normal builds
colesburymenilai bahwa dokumentasi sebaiknya ditambahkan saat variabel lingkungan diperkenalkan- Ia mendasarkan hal itu pada fakta bahwa flag configure
--disable-gilsudah didokumentasikan - Dokumen perlu memuat bahwa ini hanya tersedia pada build free-threaded,
0memaksa penonaktifan GIL,1memaksa pengaktifan GIL, dan bahwa ini adalah hal baru di Python 3.13
- Ia mendasarkan hal itu pada fakta bahwa flag configure
- Setelah itu commit
Document PYTHON_GIL environment variableditambahkan
Penambahan opsi -X gil dan penggabungan akhir
- Setelah diskusi di Discord, diputuskan untuk menambahkan opsi
-Xyang bisa dipakai bersama variabel lingkungan - Judul PR diubah dari bentuk yang hanya membahas
PYTHON_GIL=0menjadi mencakupPYTHON_GIL=0 or -X gil=0 - Commit tambahan mencakup hal-hal berikut
Add -X gil option, add to sys.flags, modify test to cover env var… and optionFix link to -X gilFix PYTHON_GIL versionchanged lineClarify test_flags in normal builds
ericsnowcurrently,erlend-aasland,corona10, dancolesburymenyetujui perubahan ini- Commit merge adalah
2731913, dan setelah mergevstinnermenanggapi perubahan ini sebagai “menarik dan sangat menakutkan”
Pekerjaan lanjutan
- Sebagai isu lanjutan, dua pekerjaan dipisahkan
- PR saat ini bukan perubahan default GIL, melainkan perubahan yang memungkinkan pengguna mengontrol status GIL pada build free-threaded melalui variabel lingkungan atau opsi
-X
1 komentar
Komentar Hacker News
Untuk yang penasaran dengan pekerjaan no-GIL, saya tinggalkan tautan tambahan: [0], [1]
[0] Multithreaded Python without the GIL
https://docs.google.com/document/d/18CXhDb1ygxg-YXNBJNzfzZsD...
[1] Repo Github
https://github.com/colesbury/nogil
[0] https://peps.python.org/pep-0703/
[1] https://github.com/colesbury/nogil-3.12
Saya menantikan seberapa jauh Python standar bisa dibuat lebih cepat. Terlalu banyak alat yang mencoba mengurangi masalah itu, sampai-sampai proposisi nilai Python sendiri ikut tertantang
Untuk alat peningkat kecepatan, yang terlintas adalah Mojo, pytorch, triton, numba, taichi. Ada begitu banyak upaya untuk memecahkan masalah ini sehingga saat terakhir kali saya mencoba salah satunya, saya kewalahan karena pilihannya terlalu banyak. Akhirnya saya memilih taichi, dan itu cukup menyenangkan serta mudah dipakai, tetapi cakupan penerapannya agak terbatas
Taichi benar-benar sangat diremehkan. Ia berjalan di semua platform, termasuk Metal, punya banyak contoh, dan penulisan kodenya mudah. Yang paling penting, ia terintegrasi dengan ekosistem dan tidak menggantikan ekosistem yang sudah ada
https://github.com/taichi-dev
Video demo luar biasa yang menunjukkan apa yang bisa dilakukan dengan Taichi: https://www.youtube.com/watch?v=oXRJoQGCYFg
https://www.youtube.com/watch?v=WNh4Q7-OSJs
https://www.taichi-lang.org/
Saya penasaran mengapa pendekatan biased reference counting yang dijelaskan di https://peps.python.org/pep-0703/ hanya mengasumsikan afinitas satu thread, lalu memerlukan increment/decrement atomik bila diakses dari thread lain
Pada implementasi lain, misalnya beberapa crate Rust yang juga menerapkan biased reference counting, saya pernah melihat pendekatan yang hanya melakukan increment atomik saat dipindahkan ke thread baru, lalu thread tersebut melakukan increment/decrement non-atomik sampai nilainya kembali ke 0, dan di akhir melakukan decrement atomik. Saya penasaran apakah ini karena implementasinya ditambahkan ke sistem yang sudah ada sehingga hanya ada satu PyObject dan tidak bisa diganti agar menunjuk ke objek lokal-thread yang baru
Di Rust, "move" untuk transfer kepemilikan adalah bagian dari bahasa, tetapi di C atau Python tidak ada konsep yang setara, jadi sulit menentukan kapan kepemilikan harus dipindahkan dan thread mana yang harus menjadi pemilik baru. Heuristik bisa dipakai. Misalnya, saat objek dimasukkan ke
queue.SimpleQueue, kepemilikan bisa dilepas atau dipindahkan, tetapi bahkan dalam kasus itu pun sulit mengetahui sebelumnya thread mana yang akan melakukan "get" pada objek di dalam queueKeuntungan performanya juga tampaknya kecil. Banyak objek hanya diakses oleh satu thread, dan sebagian objek memang diakses oleh banyak thread, tetapi objek yang awalnya diakses eksklusif oleh satu thread lalu setelah itu diakses eksklusif hanya oleh thread lain itu jarang
Tadinya saya membaca berita tentang tranched bread, dan sekarang ini juga? Zaman yang luar biasa
Saya agak kecewa saat proyek Unladen Swallow [1] meredup begitu saja. Senang melihat Python kembali ke jalur optimasi inti
[1] https://en.wikipedia.org/wiki/CPython#Unladen_Swallow
Tolong jelaskan seperti kepada anak lima tahun
Saya paham secara konsep apa itu GIL. Tapi dampak perubahan ini apa? Apakah sekarang paket-paket akan rusak sambil kita berharap ada peningkatan performa secara umum?
Bahkan kalau bukan pekerjaan CPU berat, perubahan ini tetap bisa berguna. Belakangan ini banyak kode ditulis dengan fitur bahasa asyncio bawaan Python. Ini bekerja di satu thread dengan menyerahkan eksekusi melalui async/await seperti NodeJS, dan dengan satu thread saja sudah bisa menghasilkan throughput yang cukup baik hingga ribuan request per detik
Namun masalah besarnya adalah begitu ada pekerjaan CPU apa pun dijalankan, semua coroutine lain akan ikut terblokir, sehingga muncul berbagai masalah yang samar dan throughput request per detik pun hancur. Misalnya, Anda melihat timeout I/O acak pada satu coroutine, padahal penyebab sebenarnya bisa jadi coroutine lain yang sama sekali berbeda sempat memakai CPU sejenak. Sangat sulit juga mengamati mengapa hal seperti ini terjadi. asyncio memang menyediakan fungsi
asyncio.to_thread()[1] yang membantu memindahkan pekerjaan blocking ke luar thread utama, tetapi karena adanya GIL, itu tidak benar-benar mengisolasi pekerjaan yang berfokus pada CPU agar tidak mengganggu coroutine lain[1] https://docs.python.org/3/library/asyncio-task.html#asyncio....
Untuk yang penasaran, GIL adalah singkatan dari Global Interpreter Lock
Apakah ada bahan yang merangkum gambaran besarnya dengan baik?
Akhirnya, saya menantikan benchmark berbagai alat