Halo semuanya! Senin depan, kelas akan dimulai pada grup baru kursus
Pengembang Python , yang berarti bahwa kita punya waktu untuk menerbitkan materi menarik lainnya, yang akan kita lakukan sekarang. Selamat membaca.

Kembali pada tahun 2003, Intel merilis prosesor Pentium 4 "HT" baru. Prosesor ini di-overclock ke 3GHz dan didukung teknologi hyper-threading.

Pada tahun-tahun berikutnya, Intel dan AMD berjuang untuk mencapai kinerja desktop terbaik dengan meningkatkan kecepatan bus, ukuran cache L2 dan mengurangi ukuran matriks untuk meminimalkan latensi. Pada tahun 2004, model HT dengan frekuensi 3 GHz digantikan oleh model Pres80 580 dengan overclocking ke 4 GHz.
Tampaknya untuk maju, hanya perlu meningkatkan frekuensi clock, bagaimanapun, prosesor baru menderita konsumsi daya tinggi dan pembuangan panas.
Apakah prosesor desktop Anda menghasilkan 4 GHz hari ini? Tidak mungkin, karena jalur untuk meningkatkan kinerja pada akhirnya terletak melalui peningkatan kecepatan bus dan peningkatan jumlah core. Pada tahun 2006, Intel Core 2 menggantikan Pentium 4 dan memiliki kecepatan clock yang jauh lebih rendah.
Selain merilis prosesor multi-core untuk audiens pengguna yang luas, sesuatu yang lain terjadi pada tahun 2006. Python 2.5 akhirnya melihat cahaya! Itu sudah datang dengan versi beta dari kata kunci, yang Anda semua tahu dan cinta.
Python 2.5 memiliki satu batasan utama ketika menggunakan Intel Core 2 atau AMD Athlon X2.
Itu GIL.
Apa itu GIL?
GIL (Global Interpreter Lock) adalah nilai boolean dalam interpreter Python yang dilindungi oleh mutex. Kunci tersebut digunakan dalam loop perhitungan bytecode CPython utama untuk menentukan utas mana yang sedang menjalankan instruksi.
CPython mendukung penggunaan beberapa utas dalam satu juru bahasa, tetapi utas harus meminta akses ke GIL untuk melakukan operasi tingkat rendah. Pada gilirannya, ini berarti bahwa pengembang Python dapat menggunakan kode asinkron, multithreading dan tidak perlu lagi khawatir memblokir variabel atau crash di tingkat prosesor selama kebuntuan.
GIL menyederhanakan pemrograman Python multithreaded.

GIL juga memberi tahu kita bahwa walaupun CPython dapat multi-utas, hanya satu utas sekaligus yang dapat dieksekusi. Ini berarti bahwa prosesor quad-core Anda melakukan sesuatu seperti ini (dengan pengecualian layar biru, semoga).
Versi GIL saat
ini ditulis pada tahun 2009 untuk mendukung fungsi asinkron dan tetap tidak tersentuh bahkan setelah banyak upaya untuk menghapusnya pada prinsipnya atau mengubah persyaratan untuk itu.
Setiap saran untuk menghapus GIL dibenarkan oleh fakta bahwa penguncian global dari juru bahasa tidak boleh menurunkan kinerja kode single-threaded. Siapa pun yang mencoba mengaktifkan hyperthreading pada tahun 2003 akan mengerti apa yang
saya bicarakan .
Gil ditinggalkan dalam CPython
Jika Anda ingin benar-benar memparalelkan kode dalam CPython, Anda harus menggunakan beberapa proses.
Dalam CPython 2.6, modul
multiprosesor ditambahkan ke pustaka standar. Multiprocessing menutupi proses generasi dalam CPython (setiap proses dengan GIL sendiri).
from multiprocessing import Process def f(name): print 'hello', name if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join()
Proses dibuat, perintah dikirim kepada mereka menggunakan modul yang dikompilasi dan fungsi Python, dan kemudian mereka bergabung kembali ke proses utama.
Multiprocessing juga mendukung penggunaan variabel melalui antrian atau saluran. Dia memiliki objek kunci, yang digunakan untuk mengunci objek dalam proses utama dan menulis dari proses lain.
Multiprocessing memiliki satu kelemahan utama. Ini membawa beban komputasi yang signifikan, yang memengaruhi waktu pemrosesan dan penggunaan memori. Waktu startup CPython bahkan tanpa situs adalah 100-200 ms (periksa
https://hackernoon.com/which-is-the-fastest-version-of-python-2ae7c61a6b2b untuk mempelajari lebih lanjut).
Akibatnya, Anda mungkin memiliki kode paralel dalam CPython, tetapi Anda masih perlu merencanakan pekerjaan proses jangka panjang yang berbagi beberapa objek secara hati-hati.
Alternatif lain mungkin menggunakan paket pihak ketiga seperti Twisted.
PEP554 dan kematian GIL?
Jadi, izinkan saya mengingatkan Anda bahwa multithreading di CPython sederhana, tetapi dalam kenyataannya itu bukan paralelisasi, tetapi multiprosesing paralel, tetapi memerlukan overhead yang signifikan.
Bagaimana jika ada cara yang lebih baik?Kunci untuk melewati GIL terletak pada namanya, penguncian global dari interpreter adalah bagian dari keadaan global interpreter. Proses CPython dapat memiliki beberapa penerjemah dan, oleh karena itu, beberapa kunci, bagaimanapun, fungsi ini jarang digunakan, karena akses ke sana hanya melalui C-API.
Salah satu fitur dari CPython 3.8 adalah PEP554, sebuah implementasi dari sub-interpreter dan API dengan modul
interpreters
baru di perpustakaan standar.
Ini memungkinkan Anda untuk membuat banyak interpreter dari Python dalam satu proses tunggal. Inovasi Python 3.8 lainnya adalah bahwa semua penerjemah akan memiliki GIL sendiri.

Karena status interpreter berisi wilayah yang dialokasikan dalam memori, kumpulan semua pointer ke objek Python (lokal dan global), sub-penerjemah dalam PEP554 tidak dapat mengakses variabel global dari juru bahasa lain.
Seperti multiprocessing, interpreter berbagi objek terdiri dalam serialisasi dan menggunakan bentuk IPC (jaringan, disk, atau memori bersama). Ada banyak cara untuk membuat serial objek dalam Python, misalnya, modul
marshal
, modul
pickle
, atau metode yang lebih standar seperti
json
atau
simplexml
. Masing-masing dari mereka memiliki pro dan kontra, dan semuanya memberikan beban komputasi.
Akan lebih baik untuk memiliki ruang memori bersama yang dapat diubah dan dikendalikan oleh proses tertentu. Dengan demikian, objek dapat dikirim oleh penerjemah utama dan diterima oleh penerjemah lain. Ini akan menjadi ruang memori yang dikelola untuk mencari pointer PyObject, yang dapat diakses oleh setiap penerjemah, sementara proses utama akan mengelola kunci.

API untuk ini masih sedang dikembangkan, tetapi mungkin akan terlihat seperti ini:
import _xxsubinterpreters as interpreters import threading import textwrap as tw import marshal
Contoh ini menggunakan NumPy. Array numpy dikirim melalui saluran, serial dengan menggunakan modul
marshal
, kemudian subinterpreter memproses data (pada GIL terpisah), sehingga mungkin ada masalah paralelisasi yang terkait dengan CPU, yang ideal untuk subinterpreter.
Terlihat tidak efisien
Modul
marshal
bekerja sangat cepat, tetapi tidak secepat berbagi objek langsung dari memori.
PEP574 memperkenalkan protokol
acar baru
(v5) yang mendukung kemampuan untuk memproses buffer memori secara terpisah dari sisa aliran acar. Untuk objek data besar, membuat serial semuanya dalam satu go dan deserializing dari subinterpreter akan menambah banyak overhead.
API baru dapat diimplementasikan (murni hipotetis) sebagai berikut -
import _xxsubinterpreters as interpreters import threading import textwrap as tw import pickle
Itu terlihat berpola
Intinya, contoh ini dibangun berdasarkan penggunaan API dari sub-penerjemah tingkat rendah. Jika Anda belum menggunakan pustaka
multiprocessing
, beberapa masalah akan terasa familier bagi Anda. Ini tidak sesederhana pemrosesan aliran, Anda tidak bisa, katakan saja, menjalankan fungsi ini dengan daftar data input sedemikian dalam interpreter terpisah (untuk saat ini).
Begitu PEP ini bergabung dengan yang lain, saya pikir kita akan melihat beberapa API baru di PyPi.
Berapa overhead yang dimiliki subinterpreter?
Jawaban singkat: Lebih dari sekadar streaming, kurang dari proses.
Jawaban panjang: Penerjemah memiliki statusnya sendiri, sehingga perlu mengkloning dan menginisialisasi yang berikut, meskipun fakta bahwa PEP554 menyederhanakan pembuatan sub-penerjemah:
- Modul di
__main__
dan importlib
; - Isi kamus
sys
; - Fungsi
print()
, assert
, dll.); - Stream;
- Konfigurasi kernel.
Konfigurasi kernel dapat dengan mudah dikloning dari memori, tetapi mengimpor modul tidak begitu sederhana. Mengimpor modul dengan Python lambat, jadi jika membuat subinterpreter berarti mengimpor modul ke ruang nama yang berbeda setiap kali, manfaatnya berkurang.
Bagaimana dengan asyncio?
Implementasi yang ada dari
asyncio
peristiwa
asyncio
di pustaka standar menciptakan bingkai tumpukan untuk evaluasi, dan juga
asyncio
status dalam juru bahasa utama (dan karenanya berbagi GIL).
Setelah menggabungkan PEP554, mungkin sudah di Python 3.9, implementasi alternatif dari loop acara dapat digunakan (meskipun belum ada yang melakukannya), yang menjalankan metode asinkron dalam subinterpreters secara paralel.
Kedengarannya keren, bungkus aku juga!
Yah, tidak juga.
Karena CPython telah berjalan pada juru bahasa yang sama untuk waktu yang lama, banyak bagian basis kode menggunakan "Runtime State" alih-alih "Negara Penerjemah," jadi jika PEP554 diperkenalkan sekarang, masih akan ada banyak masalah.
Misalnya, keadaan pengumpul sampah (dalam versi 3.7 <) milik runtime.
Dalam perubahan selama sprint PyCon, keadaan pengumpul sampah
mulai pindah ke penerjemah, sehingga setiap subinterpreter akan memiliki pengumpul sampah sendiri (sebagaimana mestinya).
Masalah lain adalah bahwa ada beberapa variabel "global" yang bertahan di basis kode CPython bersama dengan banyak ekstensi dalam C. Oleh karena itu, ketika orang tiba-tiba mulai memparalelkan kode mereka dengan benar, kami melihat beberapa masalah.
Masalah lain adalah bahwa deskriptor file termasuk dalam proses, jadi jika Anda memiliki file yang terbuka untuk ditulis dalam satu penerjemah, subinterpreter tidak akan dapat mengakses file ini (tanpa perubahan lebih lanjut ke CPython).
Singkatnya, masih banyak masalah yang perlu diatasi.
Kesimpulan: Apakah GIL benar lagi?
GIL akan terus digunakan untuk aplikasi single-threaded. Karena itu, bahkan ketika mengikuti PEP554, kode single-threaded Anda tiba-tiba tidak akan menjadi paralel.
Jika Anda ingin menulis kode paralel dengan Python 3.8, Anda akan memiliki masalah paralelisasi yang terkait dengan prosesor, tetapi ini juga merupakan tiket ke masa depan!
Kapan?
Pickle v5 dan berbagi memori untuk multiprosesing kemungkinan besar akan berada di Python 3.8 (Oktober 2019), dan sub-penerjemah akan muncul di antara versi 3.8 dan 3.9.
Jika Anda memiliki keinginan untuk bermain-main dengan contoh-contoh yang disajikan, maka saya membuat cabang terpisah dengan semua kode yang diperlukan:
https://github.com/tonybaloney/cpython/tree/subinterpreters.Apa yang Anda pikirkan tentang ini? Tulis komentar Anda dan sampai jumpa di kursus.