Mengapa Python Ditulis dengan GIL?


112

Global interpreter lock (GIL) tampaknya sering dikutip sebagai alasan utama mengapa threading dan sejenisnya adalah sentuhan yang rumit di Python - yang menimbulkan pertanyaan "Mengapa hal itu dilakukan sejak awal?"

Menjadi Bukan Programmer, saya tidak tahu mengapa itu mungkin - apa logika di balik menempatkan dalam GIL?


10
The artikel Wikipedia menyatakan bahwa "GIL bisa menjadi hambatan yang signifikan untuk paralelisme-harga yang dibayarkan untuk memiliki dinamika bahasa" , dan melanjutkan dengan mengatakan bahwa "Alasan untuk menggunakan kunci tersebut meliputi: peningkatan kecepatan program single-threaded (tidak ada keharusan untuk mendapatkan atau melepaskan kunci pada semua struktur data secara terpisah), dan integrasi yang mudah dari perpustakaan C yang biasanya tidak aman untuk thread. "
Robert Harvey

3
@RobertHarvey, Dynamism tidak ada hubungannya dengan itu. Masalahnya adalah mutasi.
dan_waterworth


1
Tidak bisa menahan perasaan bahwa seperti kurangnya angka Jawa yang tidak ditandatangani, itu dimaksudkan untuk mencegah orang-orang yang tidak tahu apa yang mereka lakukan menembak diri mereka sendiri. Sayangnya, orang yang tidak tahu apa yang mereka lakukan mendapat bahasa kekurangan, yang merupakan rasa malu nyata karena batu Python dalam banyak cara lain
Basic

1
@Basic harus ada beberapa cara standar untuk menangani byte array di Jawa (saya belum menggunakannya dalam waktu yang lama) untuk melakukan crypto math. Python (misalnya) tidak memiliki nomor yang ditandatangani, tetapi saya bahkan tidak akan mencoba melakukan operasi bitwise dengannya karena ada cara yang lebih baik.
Nick T

Jawaban:


105

Ada beberapa implementasi Python, misalnya, CPython, IronPython, RPython, dll.

Beberapa dari mereka memiliki GIL, beberapa tidak. Misalnya, CPython memiliki GIL:

Dari http://en.wikipedia.org/wiki/Global_Interpreter_Lock

Aplikasi yang ditulis dalam bahasa pemrograman dengan GIL dapat dirancang untuk menggunakan proses terpisah untuk mencapai paralelisme penuh, karena setiap proses memiliki penerjemah sendiri dan pada gilirannya memiliki GIL sendiri.

Manfaat GIL

  • Peningkatan kecepatan program single-threaded.
  • Integrasi yang mudah dari pustaka C yang biasanya tidak aman untuk thread.

Mengapa Python (CPython dan lainnya) menggunakan GIL

Dalam CPython, kunci juru bahasa global, atau GIL, adalah mutex yang mencegah beberapa utas asli dari mengeksekusi bytecodes Python sekaligus. Kunci ini diperlukan terutama karena manajemen memori CPython tidak aman untuk thread.

GIL kontroversial karena mencegah program CPython multithreaded dari mengambil keuntungan penuh dari sistem multiprosesor dalam situasi tertentu. Perhatikan bahwa operasi yang berpotensi memblokir atau berjalan lama, seperti I / O, pemrosesan gambar, dan pengerasan angka NumPy, terjadi di luar GIL. Oleh karena itu hanya dalam program multithreaded yang menghabiskan banyak waktu di dalam GIL, menafsirkan bytecode CPython, bahwa GIL menjadi hambatan.

Python memiliki GIL yang bertentangan dengan penguncian berbutir halus karena beberapa alasan:

  • Lebih cepat dalam kasing tunggal.

  • Lebih cepat dalam kasus multi-utas untuk program terikat i / o.

  • Lebih cepat dalam kasus multi-threaded untuk program cpu-terikat yang melakukan pekerjaan komputasi intensif di perpustakaan C.

  • Itu membuat ekstensi C lebih mudah untuk ditulis: tidak akan ada pengalihan utas Python kecuali jika Anda mengizinkannya (yaitu antara makro Py_BEGIN_ALLOW_THREADS dan Py_END_ALLOW_THREADS makro).

  • Itu membuat membungkus perpustakaan C lebih mudah. Anda tidak perlu khawatir tentang keamanan utas. Jika pustaka tidak aman thread, Anda cukup menjaga GIL terkunci saat Anda menyebutnya.

GIL dapat dirilis oleh ekstensi C. Pustaka standar Python melepaskan GIL di sekitar setiap panggilan i / o pemblokiran. Dengan demikian GIL tidak memiliki konsekuensi untuk kinerja server terikat i / o. Anda dapat membuat server jaringan di Python menggunakan proses (fork), utas atau i / o asinkron, dan GIL tidak akan menghalangi Anda.

Perpustakaan numerik di C atau Fortran juga dapat disebut dengan GIL yang dirilis. Sementara ekstensi C Anda menunggu FFT selesai, penerjemah akan mengeksekusi utas Python lainnya. Dengan demikian GIL lebih mudah dan lebih cepat daripada penguncian berbutir halus dalam kasus ini. Ini merupakan bagian terbesar dari pekerjaan numerik. Ekstensi NumPy melepaskan GIL bila memungkinkan.

Utas biasanya merupakan cara yang buruk untuk menulis sebagian besar program server. Jika beban rendah, forking lebih mudah. Jika bebannya tinggi, asynchronous i / o dan pemrograman berbasis acara (mis. Menggunakan Python's Twisted framework) lebih baik. Satu-satunya alasan untuk menggunakan utas adalah kurangnya os.fork di Windows.

GIL adalah masalah jika, dan hanya jika, Anda melakukan pekerjaan intensif CPU dengan Python murni. Di sini Anda bisa mendapatkan desain yang lebih bersih menggunakan proses dan penyampaian pesan (mis. Mpi4py). Ada juga modul 'pemrosesan' di toko keju Python, yang memberikan proses antarmuka yang sama seperti utas (yaitu ganti threading. Mulailah dengan pemrosesan. Proses).

Utas dapat digunakan untuk mempertahankan daya tanggap GUI terlepas dari GIL. Jika GIL merusak kinerja Anda (lih. Diskusi di atas), Anda dapat membiarkan utas Anda memunculkan proses dan menunggu sampai selesai.


52
Kedengarannya seperti anggur asam bagiku. Python tidak dapat melakukan utas dengan benar, jadi Anda mengarang alasan mengapa utas tidak perlu atau bahkan buruk. "Jika bebannya rendah, forking lebih mudah", serius? Dan GIL "lebih cepat" untuk semua kasus tersebut hanya jika Anda bersikeras menggunakan GC penghitungan referensi.
Michael Borgwardt

9
s/RPython/PyPy/g. @MichaelBorgwardt Memberi alasan pro GIL adalah inti dari pertanyaan, bukan? Meskipun saya akan setuju bahwa beberapa isi dari jawaban ini (yaitu diskusi tentang alternatif) tidak penting. Dan untuk lebih baik atau lebih buruk, penghitungan ulang sekarang hampir mustahil untuk dihilangkan - itu sudah mendarah daging di seluruh API dan basis kode; hampir tidak mungkin untuk menghilangkannya tanpa menulis ulang setengah kode dan menghancurkan semua kode eksternal.

10
Jangan lupa multiprocessingperpustakaan - standar sejak 2.6. Kolam pekerja adalah abstraksi super-licin untuk beberapa jenis paralelisme sederhana.
Sean McSomething

8
@alcalde Hanya jika Anda tidak tahu apa yang Anda lakukan dan / atau Anda tidak ingin utas Anda dapat bekerja secara kooperatif / berkomunikasi. Kalau tidak, itu adalah rasa sakit kerajaan di bagian belakang, terutama mengingat overhead meluncurkan proses baru pada beberapa OS. Kami memiliki server dengan 32 core, jadi untuk menggunakannya sepenuhnya dalam CPython, saya membutuhkan 32 proses. Itu bukan "solusi bagus", ini adalah peretasan untuk mengatasi kekurangan CPython.
Dasar

8
Fakta bahwa utas ada pada platform selain Windows harus cukup membuktikan bahwa forking tidak memadai dalam setiap situasi.
zneak

42

Pertama: Python tidak memiliki GIL. Python adalah bahasa pemrograman. Bahasa pemrograman adalah seperangkat aturan dan batasan matematika abstrak. Tidak ada dalam Spesifikasi Bahasa Python yang mengatakan bahwa harus ada GIL.

Ada banyak implementasi berbeda dari Python. Beberapa memiliki GIL, beberapa tidak.

Satu penjelasan sederhana untuk memiliki GIL adalah bahwa menulis kode konkuren sulit. Dengan menempatkan kunci raksasa di sekitar kode Anda, Anda memaksanya untuk selalu berjalan secara seri. Masalah terpecahkan!

Dalam CPython, khususnya, satu tujuan penting adalah untuk memudahkan memperpanjang penerjemah dengan plugin yang ditulis dalam C. Sekali lagi, menulis kode konkuren sulit, sehingga dengan menjamin bahwa tidak akan ada konkurensi, membuatnya lebih mudah untuk menulis ekstensi untuk penerjemah. Plus, banyak dari ekstensi itu hanya pembungkus tipis di sekitar perpustakaan yang ada yang mungkin belum ditulis dengan concurrency.


6
Itu argumen yang sama dengan kurangnya jenis angka Jawa yang tidak ditandatangani - para pengembang berpikir semua orang lebih bodoh daripada mereka ...
Basic

1
@Basic - percaya atau tidak, bahkan ketika Anda tidak benar-benar bodoh, ternyata memiliki bahasa yang membuat penyederhanaan asumsi yang berarti Anda tidak memikirkan hal-hal tertentu untuk membuatnya bekerja masih berguna benda. CPython sangat bagus untuk hal-hal tertentu, termasuk aplikasi multithreaded sederhana (di mana program ini terikat IO, yang banyak, dan oleh karena itu GIL tidak masalah), karena keputusan desain yang menjadikan GIL solusi terbaik juga membuat pemrograman aplikasi tersebut lebih mudah , khususnya fakta bahwa ia mendukung operasi atom pada koleksi .
Jules

@ Jules Ya, sangat praktis sampai Anda membutuhkan kemampuan itu. solusi "disukai" cpython dari "tulis saja dalam bahasa lain seperti c ++" lalu berarti Anda kehilangan setiap manfaat python tunggal. Jika Anda menulis setengah kode Anda dalam c ++, lalu mengapa mulai dari Python? Tentu, untuk proyek API / lem kecil itu cepat dan mudah, dan untuk ETL tidak ada duanya, tetapi tidak cocok untuk apa pun yang membutuhkan pengangkatan berat. Sama seperti menggunakan Java untuk berbicara dengan perangkat keras ... Ini hampir lucu lingkaran yang harus Anda lewati.
Dasar

16

Apa tujuan GIL?

Dokumentasi CAPI mengatakan ini tentang subjek:

Penerjemah Python tidak sepenuhnya aman-thread. Untuk mendukung program-program Python multi-threaded, ada kunci global, yang disebut kunci juru bahasa global atau GIL, yang harus dipegang oleh utas saat ini sebelum dapat dengan aman mengakses objek-objek Python. Tanpa kunci, bahkan operasi yang paling sederhana pun dapat menyebabkan masalah dalam program multi-ulir: misalnya, ketika dua utas secara bersamaan menambah jumlah referensi objek yang sama, jumlah referensi bisa berakhir hanya bertambah satu kali, bukan dua kali.

Dengan kata lain, GIL mencegah korupsi negara. Program python seharusnya tidak pernah menghasilkan kesalahan segmentasi, karena hanya operasi yang aman memori yang diizinkan. GIL memperluas jaminan ini ke program multi-utas.

Apa saja alternatifnya?

Jika tujuan GIL adalah untuk melindungi negara dari korupsi, maka salah satu alternatif yang jelas adalah mengunci pada butir yang jauh lebih halus; mungkin pada level per objek. Masalah dengan ini adalah bahwa meskipun telah ditunjukkan untuk meningkatkan kinerja program multi-threaded, ia memiliki lebih banyak program overhead dan single-threaded menderita sebagai hasilnya.


2
Akan lebih baik untuk membiarkan pengguna menjalankan program dengan opsi penerjemah menggantikan gil untuk kunci berbutir halus, dan entah bagaimana -dengan cara yang dibaca- apakah proses saat ini dinaikkan dengan atau tanpa gil.
Luis Masuelli

Meskipun GIL saya berhasil menghasilkan kesalahan segmentasi dalam program multithreaded karena penggunaan modul pyodbc yang ceroboh. Dengan demikian "seharusnya tidak pernah menghasilkan kesalahan segmentasi" adalah kesalahan.
Muposat
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.