Seperti yang dinyatakan sebelum ini, Arbiter adalah teras proses induk gunicorn. Arbiter bertanggungjawab terutamanya untuk mengurus proses pekerja, termasuk memulakan, memantau dan membunuh proses pekerja Pada masa yang sama, Arbiter juga boleh mengemas kini panas (muat semula) aplikasi aplikasi atau menaik taraf gunicorn dalam talian apabila isyarat tertentu berlaku. Kod teras Arbiter ada dalam satu fail, dan jumlah kod tidak besar Kod sumber ada di sini: https://github.com/benoitc/gunicorn.
Arbiter terutamanya mempunyai kaedah berikut:
persediaan:
Memproses item konfigurasi, yang paling penting ialah bilangan pekerja dan kerja pekerja model
init_signal:
Daftar fungsi pemprosesan isyarat
handle_xxx:
Fungsi pemprosesan khusus bagi setiap isyarat
bunuh_pekerja, bunuh_pekerja:
Hantar isyarat kepada proses pekerja
spawn_workers, spawn_workers:
: Berdasarkan bilangan pekerja dalam fail konfigurasi dan bilangan pekerja aktif pada masa ini, tentukan sama ada untuk menghentikan atau mematikan proses pekerjareexec
: Terima isyarat panggilan SIGUSR2, Naik Taraf gunicorn dalam talianmuat semula:
Selepas menerima panggilan SIGHUP isyarat, proses pekerja akan dimulakan berdasarkan konfigurasi baharu dan proses pekerja sebelumnya akan dimatikantidur
: Apabila tiada pemprosesan isyarat, gunakan tamat masa pilih untuk tidur dan terjagabangun
: Bangunkan proses dengan menulis mesej ke paiplari
: Gelung utamaSatu-satunya fungsi Arbiter yang sebenarnya dipanggil oleh kod lain (Application) __init__ dan kaedah jalankan, dalam satu baris kod:
Arbiter(self).run()
Diri dalam kod di atas ialah contoh Aplikasi, di mana_ _init__ memanggil persediaan untuk menetapkan item konfigurasi. Berikut ialah kod pseudo kaedah larian
def run() self.init_signal() self.LISTENERS = create_sockets(self.cfg, self.log) self.manage_workers() while True: if no signal in SIG_QUEUE self.sleep() else: handle_signal()
Mengenai proses anak forkproses anak fork Kod berada dalam spawn_worker, kod sumber adalah seperti berikut:
Proses utama:
(1) Muatkan kelas_pekerja dan instantiate (lalai ialah model segerak SyncWorker) (2) Proses induk (proses induk) kembali selepas forking, dan semua logik seterusnya dijalankan dalam proses anak
(3) Panggil pekerja. init_process untuk memasuki gelung, semua saluran baharu latihan IELTS Semua kerja dalam gelung ini
(4) Selepas gelung tamat, panggil sys.exit(0)
(5) Akhirnya, pada akhirnya, rekod keluar dari proses pekerja Berikut adalah sedikit kod yang saya tulis sendiri, yang memudahkan proses garpu utama
1 # prefork.py 2 import sys 3 import socket 4 import select 5 import os 6 import time 7 8 def do_sub_process(): 9 pid = os.fork()10 if pid < 0:11 print 'fork error'12 sys.exit(-1)13 elif pid > 0:14 print 'fork sub process %d' % pid15 return16 17 # must be child process18 time.sleep(1)19 print 'sub process will exit', os.getpid(), os.getppid()20 sys.exit(0)21 22 def main():23 sub_num = 224 for i in range(sub_num):25 do_sub_process()26 time.sleep(10)27 print 'main process will exit', os.getpid()28 29 if __name__ == '__main__':30 main()
subproses akan keluar 9601 9600
subproses akan keluar 9602 9600
Proses induk membunuh proses pekerja adalah sangat mudah Ia menghantar isyarat secara langsung 🎜>
1 def kill_worker(self, pid, sig): 2 """\ 3 Kill a worker 4 5 :attr pid: int, worker pid 6 :attr sig: `signal.SIG*` value 7 """ 8 try: 9 os.kill(pid, sig)10 except OSError as e:11 if e.errno == errno.ESRCH:12 try:13 worker = self.WORKERS.pop(pid)14 worker.tmp.close()15 self.cfg.worker_exit(self, worker)16 return17 except (KeyError, OSError):18 return19 raise
Mengenai tidur dan bangun
Mari kita lihat tidur dan bangun Arbiter. Arbiter akan "tidur" apabila tiada isyarat untuk memproses Sudah tentu, ia sebenarnya tidak memanggil masa.tidur, jika tidak isyarat tidak akan diproses serta-merta apabila ia datang. Pelaksanaan di sini lebih bijak, menggunakan paip dan pilih tamat masa. Lihat sahaja kod dan anda akan tahudef sleep(self): """\ Sleep until PIPE is readable or we timeout. A readable PIPE means a signal occurred. """ ready = select.select([self.PIPE[0]], [], [], 1.0) # self.PIPE = os.pipe() if not ready[0]: return while os.read(self.PIPE[0], 1): pass
Komen dalam kod adalah sangat jelas, sama ada PIPE boleh dibaca dan dikembalikan serta-merta, atau masa tunggu habis. Paip boleh dibaca kerana isyarat berlaku. Berikut ialah lihat fungsi paip
()
boleh digunakan untuk membaca dan menulis, masing -masing. fungsi
def wakeup(self): """ Wake up the arbiter by writing to the PIPE """ os.write(self.PIPE[1], b'.')
Keluar, INT: Tutup pantas os.
pipe
TERMA: Penutupan yang anggun. Menunggu pekerja menyelesaikan permintaan semasa sehingga tamat masa.
HUP: Muat semula konfigurasi, mulakan proses pekerja baharu dengan konfigurasi baharu dan tutup proses pekerja lama dengan anggun. Gunicorn juga akan memuatkan versi baharu jika aplikasi tidak dipramuat (menggunakan pilihan --preload).
TTIN: Tingkatkan bilangan proses sebanyak satu
TTOU: Kurangkan bilangan proses sebanyak satu
USR1: Buka semula fail log
USR2: Naik taraf Gunicorn dengan pantas. Isyarat istilah yang berasingan harus digunakan untuk menamatkan proses lama. Isyarat ini juga boleh digunakan untuk menggunakan versi aplikasi baharu yang dipramuat.
Winch: Matikan proses pekerja dengan anggun apabila Gunicorn didaemonkan.
Atas ialah kandungan terperinci Bagaimana untuk menganalisis kod sumber Arbiter gunicorn. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!