Apa itu kunci juru bahasa global dan mengapa itu menjadi masalah?
Banyak suara telah dibuat sekitar menghapus GIL dari Python, dan saya ingin mengerti mengapa itu sangat penting. Saya belum pernah menulis kompiler atau penerjemah sendiri, jadi jangan hemat dengan detail, saya mungkin perlu mereka mengerti.
python
python-internals
gil
e-satis
sumber
sumber
Jawaban:
GIL Python dimaksudkan untuk membuat serial akses ke interpreter internals dari utas yang berbeda. Pada sistem multi-core, ini berarti bahwa beberapa utas tidak dapat secara efektif memanfaatkan banyak inti. (Jika GIL tidak mengarah ke masalah ini, kebanyakan orang tidak akan peduli dengan GIL - itu hanya diangkat sebagai masalah karena meningkatnya prevalensi sistem multi-inti.) Jika Anda ingin memahaminya secara rinci, Anda dapat melihat video ini atau melihat kumpulan slide ini . Mungkin terlalu banyak informasi, tetapi kemudian Anda memang meminta detail :-)
Perhatikan bahwa GIL Python hanya benar-benar masalah untuk CPython, implementasi referensi. Jython dan IronPython tidak memiliki GIL. Sebagai pengembang Python, Anda biasanya tidak menemukan GIL kecuali Anda sedang menulis ekstensi C. Penulis ekstensi C perlu melepaskan GIL ketika ekstensi mereka memblokir I / O, sehingga utas lain dalam proses Python mendapatkan kesempatan untuk berjalan.
sumber
regex
,lxml
,numpy
modul. Cython memungkinkan untuk melepaskan GIL dalam kode khusus misalnya,b2a_bin(data)
Misalkan Anda memiliki banyak utas yang tidak benar - benar menyentuh data satu sama lain. Mereka harus mengeksekusi sebebas mungkin. Jika Anda memiliki "kunci global" yang perlu Anda peroleh untuk (katakanlah) memanggil fungsi, itu bisa berakhir sebagai hambatan. Anda bisa mendapatkan banyak manfaat dengan memiliki banyak utas.
Untuk membuatnya menjadi analogi dunia nyata: bayangkan 100 pengembang bekerja di sebuah perusahaan dengan hanya satu cangkir kopi. Sebagian besar pengembang akan menghabiskan waktu menunggu kopi alih-alih menulis kode.
Tak satu pun dari ini adalah Python-spesifik - Saya tidak tahu rincian apa yang dibutuhkan Python untuk GIL di tempat pertama. Namun, semoga ini memberi Anda ide yang lebih baik dari konsep umum.
sumber
Pertama mari kita memahami apa yang disediakan oleh python GIL:
Setiap operasi / instruksi dieksekusi dalam juru bahasa. GIL memastikan bahwa penerjemah dipegang oleh satu utas pada saat tertentu . Dan program python Anda dengan banyak utas berfungsi dalam satu juru bahasa. Pada saat tertentu, juru bahasa ini dipegang oleh satu utas. Ini berarti bahwa hanya benang yang memegang interpreter yang berjalan di sembarang waktu .
Sekarang mengapa itu menjadi masalah:
Mesin Anda dapat memiliki beberapa inti / prosesor. Dan beberapa core memungkinkan banyak thread untuk dieksekusi secara bersamaan yaitu beberapa thread dapat dieksekusi pada saat tertentu. . Tetapi karena penerjemah dipegang oleh satu utas, utas lainnya tidak melakukan apa pun meskipun mereka memiliki akses ke inti. Jadi, Anda tidak mendapatkan keuntungan apa pun yang disediakan oleh beberapa inti karena pada saat apa pun hanya satu inti, yang merupakan inti yang digunakan oleh utas yang saat ini memegang juru bahasa, sedang digunakan. Jadi, program Anda akan membutuhkan waktu lama untuk dieksekusi seolah-olah itu adalah program berulir tunggal.
Namun, operasi yang berpotensi memblokir atau berjalan lama, seperti I / O, pemrosesan gambar, dan angka NumPy, terjadi di luar GIL. Diambil dari sini . Jadi untuk operasi seperti itu, operasi multithreaded akan tetap lebih cepat daripada operasi threaded tunggal meskipun ada GIL. Jadi, GIL tidak selalu menjadi hambatan.
Sunting: GIL adalah detail implementasi CPython. IronPython dan Jython tidak memiliki GIL, jadi program yang benar-benar multithreaded mungkin ada di dalamnya, pikir saya belum pernah menggunakan PyPy dan Jython dan tidak yakin akan hal ini.
sumber
Python tidak mengizinkan multi-threading dalam arti kata yang sebenarnya. Ini memiliki paket multi-threading tetapi jika Anda ingin multi-thread untuk mempercepat kode Anda, maka itu biasanya bukan ide yang baik untuk menggunakannya. Python memiliki konstruk yang disebut Global Interpreter Lock (GIL).
https://www.youtube.com/watch?v=ph374fJqFPE
GIL memastikan bahwa hanya satu dari 'utas' Anda yang dapat dieksekusi pada satu waktu. Sebuah thread mendapatkan GIL, melakukan sedikit pekerjaan, lalu meneruskan GIL ke thread berikutnya. Hal ini terjadi sangat cepat sehingga bagi mata manusia, sepertinya utas Anda berjalan paralel, tetapi mereka benar-benar hanya bergantian menggunakan inti CPU yang sama. Semua operan GIL ini menambah biaya eksekusi. Ini berarti bahwa jika Anda ingin membuat kode Anda berjalan lebih cepat maka menggunakan paket threading sering bukan ide yang baik.
Ada alasan untuk menggunakan paket threading Python. Jika Anda ingin menjalankan beberapa hal secara bersamaan, dan efisiensi bukan masalah, maka itu benar-benar baik dan nyaman. Atau jika Anda menjalankan kode yang perlu menunggu sesuatu (seperti IO) maka itu bisa masuk akal. Tetapi pustaka threading tidak akan membiarkan Anda menggunakan core CPU tambahan.
Multi-threading dapat dialihdayakan ke sistem operasi (dengan melakukan multi-pemrosesan), beberapa aplikasi eksternal yang memanggil kode Python Anda (misalnya, Spark atau Hadoop), atau beberapa kode yang panggilan kode Python Anda (misalnya: Anda dapat memiliki Python Anda panggilan kode fungsi C yang melakukan hal-hal multi-threaded mahal).
sumber
Setiap kali dua utas memiliki akses ke variabel yang sama Anda memiliki masalah. Dalam C ++ misalnya, cara untuk menghindari masalah adalah dengan mendefinisikan beberapa kunci mutex untuk mencegah dua utas, katakanlah, masukkan penyetel objek pada saat yang sama.
Multithreading dimungkinkan dalam python, tetapi dua utas tidak dapat dieksekusi pada saat yang sama pada granularity yang lebih baik daripada satu instruksi python. Utas yang menjalankan mendapatkan kunci global yang disebut GIL.
Ini berarti jika Anda mulai menulis beberapa kode multithread untuk memanfaatkan prosesor multicore Anda, kinerja Anda tidak akan membaik. Solusi yang biasa terdiri dari proses multiproses.
Perhatikan bahwa dimungkinkan untuk melepaskan GIL jika Anda menggunakan metode yang Anda tulis dalam C misalnya.
Penggunaan GIL tidak melekat pada Python tetapi untuk beberapa penerjemahnya, termasuk CPython yang paling umum. (#edited, lihat komentar)
Masalah GIL masih valid dalam Python 3000.
sumber
Dokumentasi Python 3.7
Saya juga ingin menyoroti kutipan berikut dari dokumentasi Python
threading
:Tautan ini ke entri Glosarium
global interpreter lock
yang menjelaskan bahwa GIL menyiratkan bahwa paralelisme berulir dalam Python tidak cocok untuk tugas yang terikat CPU :Kutipan ini juga menyiratkan bahwa dikt dan karenanya penugasan variabel juga aman sebagai detail implementasi CPython:
Selanjutnya, dokumen untuk
multiprocessing
paket menjelaskan bagaimana mengatasi GIL dengan proses pemijahan sambil mengekspos antarmuka yang mirip denganthreading
:Dan dokumen untuk
concurrent.futures.ProcessPoolExecutor
menjelaskan itu digunakanmultiprocessing
sebagai backend:yang harus dikontraskan dengan kelas dasar lainnya
ThreadPoolExecutor
yang menggunakan utas bukannya prosesdari mana kami menyimpulkan bahwa
ThreadPoolExecutor
hanya cocok untuk tugas terikat I / O, sementaraProcessPoolExecutor
juga dapat menangani tugas terikat CPU.Pertanyaan berikut menanyakan mengapa GIL ada di tempat pertama: Mengapa Global Interpreter Lock?
Percobaan proses vs utas
Di Multiprocessing vs Threading Python saya telah melakukan analisis eksperimental proses vs threads di Python.
Pratinjau cepat hasil:
sumber
Mengapa Python (CPython dan lainnya) menggunakan GIL
Dari http://wiki.python.org/moin/GlobalInterpreterLock
Dalam CPython, kunci juru bahasa global, atau GIL, adalah mutex yang mencegah beberapa utas asli mengeksekusi bytecode Python sekaligus. Kunci ini diperlukan terutama karena manajemen memori CPython tidak aman untuk thread.
Bagaimana cara menghapusnya dari Python?
Seperti Lua, mungkin Python dapat memulai banyak VM, Tapi python tidak melakukan itu, saya kira harus ada beberapa alasan lain.
Dalam Numpy atau pustaka diperluas python lainnya, kadang-kadang, melepaskan GIL ke utas lain dapat meningkatkan efisiensi seluruh program.
sumber
Saya ingin berbagi contoh dari buku multithreading untuk Efek Visual. Jadi di sini adalah situasi kunci mati klasik
Sekarang pertimbangkan kejadian dalam urutan yang menghasilkan dead-lock.
sumber