Apakah Python GIL, cara ia berfungsi dan cara ia mempengaruhi gunicorn.
Jenis pekerja Gunicorn yang manakah harus saya pilih untuk persekitaran pengeluaran?
Python mempunyai kunci global (GIL) yang hanya membenarkan satu utas dijalankan (iaitu mentafsir kod bait). Pada pendapat saya, memahami cara Python mengendalikan concurrency adalah penting jika anda ingin mengoptimumkan perkhidmatan Python anda.
Python dan gunicorn memberi anda cara yang berbeza untuk mengendalikan konkurensi, dan memandangkan tiada peluru ajaib yang merangkumi semua kes penggunaan, adalah lebih baik untuk memahami pilihan, tukar ganti dan kelebihan setiap pilihan.
Gunicorn mendedahkan pilihan berbeza ini di bawah konsep "jenis pekerja". Setiap jenis sesuai untuk set kes penggunaan tertentu.
Ini adalah jenis pekerjaan yang paling mudah di mana satu-satunya pilihan serentak ialah memotong proses N yang akan melayani permintaan secara selari.
Ia boleh berfungsi dengan baik, tetapi menanggung banyak overhed (seperti memori dan penukaran konteks CPU), dan jika kebanyakan masa permintaan anda menunggu I/O, penskalaan Sex ialah teruk.
gthread worker menambah baik perkara ini dengan membenarkan anda membuat N thread setiap proses. Ini meningkatkan prestasi I/O kerana anda boleh menjalankan lebih banyak contoh kod anda secara serentak. Ini adalah satu-satunya daripada empat yang terjejas oleh GIL.
eventlet/gevent pekerja cuba menambah baik lagi model gthread dengan menjalankan utas pengguna yang ringan (aka benang hijau, greenlet, dll.).
Ini membolehkan anda memiliki beribu-ribu greenlet tersebut pada kos yang sangat kecil berbanding dengan rangkaian sistem. Perbezaan lain ialah model ini mengikuti model kerja kolaboratif dan bukannya preemptive, membenarkan kerja tanpa gangguan sehingga ia disekat. Kami mula-mula akan menganalisis kelakuan benang pekerja gthread semasa memproses permintaan dan cara ia dipengaruhi oleh GIL.
Tidak seperti penyegerakan di mana setiap permintaan disampaikan secara langsung oleh satu proses, dengan gthread, setiap proses mempunyai N urutan untuk penskalaan yang lebih baik tanpa menimbulkan berbilang proses overhed. Memandangkan anda menjalankan berbilang benang dalam proses yang sama, GIL akan menghalangnya daripada berjalan secara selari.
GIL bukanlah satu proses atau benang khas. Ia hanyalah pembolehubah boolean yang aksesnya dilindungi oleh mutex, yang memastikan bahawa hanya satu utas berjalan dalam setiap proses. Bagaimana ia berfungsi boleh dilihat pada gambar di atas. Dalam contoh ini kita dapat melihat bahawa kita mempunyai 2 utas sistem berjalan serentak, setiap utas mengendalikan 1 permintaan. Prosesnya adalah seperti ini:
Pilihan lain untuk meningkatkan konkurensi tanpa menggunakan proses ialah menggunakan greenlets. Pekerja ini menghasilkan "benang pengguna" dan bukannya "benang sistem" untuk meningkatkan serentak.
Walaupun ini bermakna mereka tidak terjejas oleh GIL, ini juga bermakna anda masih tidak boleh meningkatkan selari kerana ia tidak boleh dijadualkan selari oleh CPU.
Untuk kes ini, adalah jelas bahawa mempunyai pekerja jenis greenlet adalah tidak ideal. Kami akhirnya mempunyai permintaan kedua menunggu sehingga permintaan pertama selesai dan kemudian melahu menunggu I/O sekali lagi.
Model kerjasama greenlet benar-benar bersinar dalam senario ini kerana anda tidak membuang masa pada suis konteks dan mengelakkan overhed menjalankan berbilang rangkaian sistem.
Kami akan menyaksikan ini dalam ujian penanda aras pada akhir artikel ini. Sekarang, ini menimbulkan persoalan berikut:
Untuk menjawab soalan ini, anda perlu memantau untuk mengumpulkan metrik yang diperlukan dan kemudian menjalankan penanda aras yang disesuaikan terhadap metrik yang sama tersebut. Tiada guna menjalankan penanda aras sintetik yang mempunyai korelasi sifar dengan corak penggunaan sebenar anda. Graf di bawah menunjukkan kependaman dan metrik daya pemprosesan untuk senario yang berbeza untuk memberi anda gambaran tentang cara semuanya berfungsi bersama.
Di sini kita dapat melihat cara menukar selang penukaran/tamat masa penukaran benang GIL mempengaruhi kependaman permintaan. Seperti yang dijangkakan, kependaman IO menjadi lebih baik apabila selang pensuisan berkurangan. Ini berlaku kerana utas terikat CPU terpaksa melepaskan GIL dengan lebih kerap dan membenarkan utas lain menyelesaikan kerja mereka.
Tetapi ini bukan ubat penawar. Mengurangkan selang suis akan menjadikan benang terikat CPU mengambil masa lebih lama untuk disiapkan. Kita juga boleh melihat peningkatan dalam kependaman keseluruhan dan pengurangan dalam tamat masa disebabkan peningkatan overhed penukaran benang berterusan. Jika anda ingin mencuba sendiri, anda boleh menukar selang penukaran menggunakan kod berikut:
Secara keseluruhannya, kami dapat melihat bahawa penanda aras mencerminkan gerak hati kami daripada analisis kami sebelum ini tentang cara benang dan greenlet terikat GIL berfungsi.
Gthread mempunyai kependaman purata yang lebih baik untuk permintaan terikat IO disebabkan oleh pertukaran selang yang memaksa benang berjalan lama dilepaskan.
permintaan terikat CPU gevent mempunyai kependaman yang lebih baik daripada gthread kerana ia tidak terganggu untuk memberi perkhidmatan kepada permintaan lain.
Hasil di sini juga mencerminkan perbandingan gevent vs. gthread Intuisi kami sebelum ini untuk lebih baik daya pengeluaran. Penanda aras ini sangat bergantung pada jenis kerja yang dilakukan dan mungkin tidak semestinya diterjemahkan terus kepada kes penggunaan anda.
Matlamat utama penanda aras ini adalah untuk memberi anda sedikit panduan tentang perkara yang perlu diuji dan diukur untuk memaksimumkan setiap teras CPU yang akan melayani permintaan.
Memandangkan semua pekerja gunicorn membenarkan anda menentukan bilangan proses yang akan dijalankan, apa yang berubah ialah cara setiap proses mengendalikan sambungan serentak. Oleh itu, pastikan anda menggunakan bilangan pekerja yang sama untuk menjadikan ujian itu adil. Sekarang mari cuba jawab soalan sebelumnya menggunakan data yang dikumpul daripada penanda aras kami.
Itu benar. Walau bagaimanapun, untuk sebahagian besar beban kerja, ini bukan pengubah permainan.
Bagaimana untuk memilih antara gevent/eventlet dan gthread apabila anda bekerja dengan I/O dan CPU bercampur? Seperti yang dapat kita lihat, ghtread cenderung untuk membenarkan keselarasan yang lebih baik apabila anda mempunyai kerja yang lebih intensif CPU.
Selagi penanda aras anda boleh mensimulasikan gelagat seperti pengeluaran, anda akan melihat dengan jelas prestasi puncak dan kemudian ia akan mula merosot kerana terlalu banyak urutan.
Perlukah saya hanya menggunakan pekerja penyegerakan dan menambah bilangan proses bercabang untuk mengelakkan GIL?
Melainkan I/O anda hampir sifar, penskalaan dengan proses sahaja bukanlah pilihan terbaik.
Coroutine/Greenlets boleh meningkatkan kecekapan CPU kerana ia mengelakkan gangguan dan suis konteks antara urutan. Coroutines berdagang kependaman untuk pemprosesan.
Coroutine boleh menyebabkan kependaman yang lebih tidak dapat diramalkan jika anda mencampurkan IO dan titik akhir terikat CPU - Titik akhir terikat CPU tidak terganggu untuk melayani permintaan masuk yang lain. Jika anda meluangkan masa untuk mengkonfigurasi gunicorn dengan betul, GIL tidak menjadi masalah.
Atas ialah kandungan terperinci Fahami Gunicorn dan Python GIL dalam satu artikel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!